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可能没有.如果是这种情况除了使用指针之外还有什么方法可以显式删除它吗?
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
超出范围时,它会以同样的方式被破坏.在任何时候都不需要手动删除它,因为所有内容都在堆栈上分配.
该术语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)
它在堆栈上需要多少空间?
根据这些假设,它需要 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
消失)
正如您可能注意到的......实际上很难猜测编译器/优化器将能够做什么。如果您确实有严格的内存需求,那么(也许令人惊讶),您最好的选择可能是用函数替换块。