是否在C++的特定情况下删除了没有删除新运算符的对象

sie*_*nko 6 c++ object new-operator

如果我们有以下代码段:

MyObject my_object = MyObject(0);
my_object = MyObject(1);
Run Code Online (Sandbox Code Playgroud)

MyObject(0)会发生什么?它被删除了吗?看看我读到的内容,只有当我们离开创建范围时才应删除它,因此anwser可能没有.如果是这种情况除了使用指针之外还有什么方法可以显式删除它吗?

gre*_*olf 5

MyObject my_object = MyObject(0);
Run Code Online (Sandbox Code Playgroud)

这一行my_object使用MyObject可以接受的构造函数在堆栈上创建int.

my_object = MyObject(1);
Run Code Online (Sandbox Code Playgroud)

此行再次使用与第一个相同的构造函数创建临时 MyObject.然后my_object通过调用赋值运算符来分配它.如果您没有提供此运算符,则编译器将为您执行一个执行复制的运算符.当此语句完成时,临时MyObject超出范围并调用它的析构函数.

当你my_object超出范围时,它会以同样的方式被破坏.在任何时候都不需要手动删除它,因为所有内容都在堆栈上分配.


Mat*_* M. 1

该术语delete在 C++ 中具有特殊含义,因此使用删除是不幸的。

MyObject my_object = MyObject(0);
Run Code Online (Sandbox Code Playgroud)

这一行声明了一个MyObject具有自动存储持续时间(即在堆栈上)创建的类型的对象。当作用域结束时,该对象将被析构(即,其析构函数将被执行)。标准中没有对相关记忆的回忆做出规定(见后面的例子)。

该类型的对象MyObject将使用表达式构造MyObject(0)。该构造函数将初始化专门为其专用的内存。

注意:实际上,可以创建一个临时变量,然后调用复制构造函数,但幸运的是,大多数编译器都避开了这个中间步骤,因为标准明确允许这样做。

my_object = MyObject(1);
Run Code Online (Sandbox Code Playgroud)

该行将由表达式 确定的新值分配MyObject(1)给已存在的my_object对象。为此,MyObject将创建具有自动存储持续时间的临时类型。然后,执行赋值运算符;如果没有重载,它将把临时的状态复制到my_object,擦除之前的状态。在表达式结束时,临时变量被破坏(再次,没有为相关内存的回收提供任何准备)。

注意:MyObject(0)不是“删除”,因为它不存在,而是重新使用它写入状态的内存来复制状态MyObject(1)


正如所承诺的,既然这似乎是您的担忧,那么就内存方面进行讨论。这是特定于编译器的,但大多数编译器的行为类似。

假设我们有以下函数:

void f() {
  MyObject my_object = MyObject(0);

  {
    my_object = MyObject(1);
    do_something(my_object);
  }

  {
    my_object = MyObject(2);
    do_something(my_object);
  }
}
Run Code Online (Sandbox Code Playgroud)

它在堆栈上需要多少空间?

  • 我们假设它在第一行执行直接构造
  • 我们假设编译器不够智能,无法执行堆栈着色(例如,Clang 就没有)

根据这些假设,它需要 3 的空间MyObject

  • MyObject my_object = MyObject(0);:my_object需要一直存活到函数结束
  • my_object = MyObject(1);: 临时需要创建
  • my_object = MyObject(2);: 临时需要创建

函数执行结束时会回收堆栈空间。

如果编译器足够智能来执行堆栈着色,那么两个临时对象(永远不需要一起使用)可以使用相同的内存点,从而将空间需求降低到 2 MyObject

智能优化器也可能直接构建MyObject(1)MyObject(2)直接进入my_object(如果它可以证明效果与构建临时然后复制它相同),从而将空间需求降低到 1 MyObject

最后,如果 的定义do_something是可见的,并且它不使用其参数,那么在某些条件下它可以(理论上)完全绕过 的构造my_object。这种优化可以通过简单的程序来见证,例如:

int main() { int i = 0; for (; i < 1000; ++i); return i; }
Run Code Online (Sandbox Code Playgroud)

其经过简单优化以:

int main() { return 1000; }
Run Code Online (Sandbox Code Playgroud)

(注意如何i消失)

正如您可能注意到的......实际上很难猜测编译器/优化器将能够做什么。如果您确实有严格的内存需求,那么(也许令人惊讶),您最好的选择可能是用函数替换块。