【发布时间】:2014-03-22 19:57:45
【问题描述】:
如果我在堆栈上声明了一个对象,并且我返回了对它的引用,我相信我将无法再访问它,因为它超出了范围。对吗?
如果我只返回对象本身(而不是对它的引用)怎么办?会调用复制构造函数吗? (我听说过“移动构造函数”这个词,但从我的阅读来看,它似乎是一个新功能。有人可以详细说明一下吗?)
在什么情况下会调用析构函数?
【问题讨论】:
标签: c++ scope copy-constructor move-constructor
如果我在堆栈上声明了一个对象,并且我返回了对它的引用,我相信我将无法再访问它,因为它超出了范围。对吗?
如果我只返回对象本身(而不是对它的引用)怎么办?会调用复制构造函数吗? (我听说过“移动构造函数”这个词,但从我的阅读来看,它似乎是一个新功能。有人可以详细说明一下吗?)
在什么情况下会调用析构函数?
【问题讨论】:
标签: c++ scope copy-constructor move-constructor
如果我在堆栈上声明了一个对象,并且我返回了对它的引用,我相信我将无法再访问它,因为它超出了范围。对吗?
正确,析构函数超出范围时会被调用。
如果我只返回对象本身(而不是对它的引用)怎么办?会调用复制构造函数吗?
可以调用复制构造函数和析构函数,但通常编译器会执行返回值优化,不会进行复制、析构函数或移动。
要了解移动构造函数,请阅读移动语义和右值引用。
【讨论】:
如果我在堆栈上声明了一个对象,并且我返回了对它的引用,我相信我将无法再访问它,因为它超出了范围。对吗?
正确,许多编译器也会给你警告。
如果我只返回对象本身(而不是对它的引用)怎么办?会调用复制构造函数吗?
它会调用复制构造函数。标准的 std::array 没有 std::move 构造函数在内部定义为它使用堆栈内存。 因此将调用复制构造函数。
在什么情况下会调用析构函数?
在这两种情况下都会调用析构函数。只是在移动构造函数之后,我们将所有指针/句柄移动到其他对象,因此对象状态将是一种空(但一致)。
【讨论】:
编译器将尝试优化此类函数以消除复制操作。生成的代码将表现得好像对象是在函数以适当的生命周期返回它的点创建的。参考here。 这取决于编译器,以及代码本身在构造和使用点的结构。也可能无法进行优化,在这种情况下,您可能需要调用复制或移动构造函数(如果可用)。
如果编译器对函数进行了优化,那么当使用点的对象超出最近的块范围时,将调用析构函数。
如果没有优化,那么对象会在使用点被复制到另一个(一次调用复制/移动构造函数),然后函数中的对象将被销毁(如果被复制),最后是析构函数复制/移动的对象将在函数返回它的位置(使用点)离开最近的块范围时被调用。
但是,如果您从函数返回一个临时对象,那么您将返回一个指向已破坏内存的引用或指针,因为您的临时对象将在函数返回时超出范围并被销毁。
【讨论】: