new[],delete[]复杂性

2023-12-27

我已经知道new[]运算符首先分配内存,然后为每个元素调用构造函数,并且delete[]运算符首先为每个元素调用析构函数,然后释放内存,因此,它们的时间复杂度都是 O(n)。

但是,如果我有一个类,我没有为其定义任何构造函数/析构函数,那么复杂度仍然是 O(n),还是只是 O(1)?

例如,如果我有两个课程:

class foo
{
public:
    int a;
    foo()
    {
        a = 0;
        // more stuff
    }
    ~foo()
    {
        a = 1;
        // some useful stuff here
    }
};

class boo
{
public:
    int a;
};

我创建了两个数组,如下所示:

int n = 1000;
foo* pfoo = new foo[n];
boo* pboo = new boo[n];

我很确定第一个new调用的复杂度为 O(n),但是第二个呢?将要new只需分配必要的内存就可以了,或者它会为每个元素调用一些默认构造函数(我不确定这样的东西是否真的存在于 C++ 中)?

同样的问题delete:

delete [] pfoo;
delete [] pboo;

当我删除第二个数组时,复杂度仍然是 O(n),还是会delete只是以 O(1) 复杂度释放内存?


当您不知道时,使用汇编输出是个好主意。例如,我们假设这是要比较的代码。

class foo
{
public:
    int a;
    foo()
    {
        a = 0;
        // more stuff
    }
    ~foo()
    {
        a = 1;
        // some useful stuff here
    }
};

class boo
{
public:
    int a;
};

void remove_foo(foo* pfoo) {
    delete [] pfoo;
}

void remove_boo(boo *pboo) {
    delete [] pboo;
}

当使用 gcc 进行优化编译时(Clang 给出类似的输出),您将得到以下结果。

    .file   "deleter.cpp"
    .text
    .p2align 4,,15
    .globl  _Z10remove_fooP3foo
    .type   _Z10remove_fooP3foo, @function
_Z10remove_fooP3foo:
.LFB6:
    .cfi_startproc
    testq   %rdi, %rdi
    je  .L1
    movq    -8(%rdi), %rax
    leaq    (%rdi,%rax,4), %rax
    cmpq    %rax, %rdi
    je  .L4
    .p2align 4,,10
    .p2align 3
.L6:
    subq    $4, %rax
    movl    $1, (%rax)
    cmpq    %rax, %rdi
    jne .L6
.L4:
    subq    $8, %rdi
    jmp _ZdaPv
    .p2align 4,,10
    .p2align 3
.L1:
    rep ret
    .cfi_endproc
.LFE6:
    .size   _Z10remove_fooP3foo, .-_Z10remove_fooP3foo
    .p2align 4,,15
    .globl  _Z10remove_booP3boo
    .type   _Z10remove_booP3boo, @function
_Z10remove_booP3boo:
.LFB7:
    .cfi_startproc
    testq   %rdi, %rdi
    je  .L8
    jmp _ZdaPv
    .p2align 4,,10
    .p2align 3
.L8:
    rep ret
    .cfi_endproc
.LFE7:
    .size   _Z10remove_booP3boo, .-_Z10remove_booP3boo
    .ident  "GCC: (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]"
    .section    .note.GNU-stack,"",@progbits

很容易看出foo它调用析构函数,但是对于boo它直接调用delete []功能 (_ZdaPv名称修改后)。在没有优化的情况下也会发生这种情况。代码较长,因为实际上是输出方法,但仍然值得注意的是delete []被直接调用boo.

    .file   "deleter.cpp"
    .section    .text._ZN3fooD2Ev,"axG",@progbits,_ZN3fooD5Ev,comdat
    .align 2
    .weak   _ZN3fooD2Ev
    .type   _ZN3fooD2Ev, @function
_ZN3fooD2Ev:
.LFB4:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movl    $1, (%rax)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE4:
    .size   _ZN3fooD2Ev, .-_ZN3fooD2Ev
    .weak   _ZN3fooD1Ev
    .set    _ZN3fooD1Ev,_ZN3fooD2Ev
    .text
    .globl  _Z10remove_fooP3foo
    .type   _Z10remove_fooP3foo, @function
_Z10remove_fooP3foo:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $24, %rsp
    .cfi_offset 3, -24
    movq    %rdi, -24(%rbp)
    cmpq    $0, -24(%rbp)
    je  .L3
    movq    -24(%rbp), %rax
    subq    $8, %rax
    movq    (%rax), %rax
    leaq    0(,%rax,4), %rdx
    movq    -24(%rbp), %rax
    leaq    (%rdx,%rax), %rbx
.L6:
    cmpq    -24(%rbp), %rbx
    je  .L5
    subq    $4, %rbx
    movq    %rbx, %rdi
    call    _ZN3fooD1Ev
    jmp .L6
.L5:
    movq    -24(%rbp), %rax
    subq    $8, %rax
    movq    %rax, %rdi
    call    _ZdaPv
.L3:
    addq    $24, %rsp
    popq    %rbx
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   _Z10remove_fooP3foo, .-_Z10remove_fooP3foo
    .globl  _Z10remove_booP3boo
    .type   _Z10remove_booP3boo, @function
_Z10remove_booP3boo:
.LFB7:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movq    %rdi, -8(%rbp)
    cmpq    $0, -8(%rbp)
    je  .L7
    movq    -8(%rbp), %rax
    movq    %rax, %rdi
    call    _ZdaPv
.L7:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE7:
    .size   _Z10remove_booP3boo, .-_Z10remove_booP3boo
    .ident  "GCC: (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]"
    .section    .note.GNU-stack,"",@progbits

这也适用于new []. _Znam直接调用,无需构造对象,甚至无需优化。

一般来说,这意味着自定义构造函数或析构函数意味着new [] and delete []不会在恒定时间内执行。但如果没有,编译器不会尝试调用这些对象的构造函数或析构函数,它们将是 POD 数据类型,这意味着构造这些对象是简单的类似 malloc 的调用。有一些例外(涉及各种优化),但通常带有构造函数/析构函数的代码将是 O(N),而没有构造函数/析构函数的代码将是 O(1),假设 O(1)new []/delete []执行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

new[],delete[]复杂性 的相关文章

  • 更新面板工作速度非常慢

    我正在编写一个用户可以注册的应用程序 注册时 可以选择多个选项 并根据这些注册字段可见或不可见以及是否必需 我想出了一个想法 所有字段都将位于 updatePanel 中 当用户更改注册选项时 我将在服务器端设置这些字段的可见性 它可以工作
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • Rx.NET 中是否有一个Subject 实现,其功能类似于BehaviourSubject,但仅在值发生更改时才发出?

    有没有Subject https learn microsoft com en us previous versions dotnet reactive extensions hh229699 v vs 103 Rx NET 中的实现在功能
  • 前向声明类型和“已声明为类类型的非类类型”

    我对以下代码有问题 template
  • java中如何重新初始化int数组

    class PassingRefByVal static void Change int pArray pArray 0 888 This change affects the original element pArray new int
  • 在 VS 中运行时如何查看 C# 控制台程序的输出?

    我刚刚编写了一个名为 helloworld 的聪明程序 它是一个 C NET 4 5 控制台应用程序 在扭曲的嵌套逻辑迷宫深处 使用了 Console WriteLine 当我在命令行运行它时 它会运行并且我会看到输出 我可以执行其他命令并
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • 在 C 中使用枚举而不是 #defines 作为编译时常量是否合理?

    在 C 工作了一段时间后 我将回到 C 开发领域 我已经意识到 在不必要的时候应该避免使用宏 以便让编译器在编译时为您做更多的工作 因此 对于常量值 在 C 中我将使用静态 const 变量或 C 11 枚举类来实现良好的作用域 在 C 中
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • 我可以使用 lambda 函数或 std::function 对象来代替函数指针吗?

    我有一个需要使用的库 它定义了以下内容 typedef void CallbackFunction const int i 并且有一个注册回调的函数 如下所示 void registerCallback CallbackFunction p
  • 当用户更改 Windows 中的语言键盘布局时如何通知?

    I want to show a message to user when the user changes the language keyboard layout of Windows for example from EN to FR

随机推荐