在 C++ 中,如果您在堆栈上(在函数内)创建一个对象并将其插入到堆分配的容器中(该容器已被传递到函数中/在函数完成后存在),会发生什么?
堆栈对象具有本地范围,但它已插入其中的容器位于堆上,并且可以在函数(进行插入的位置)返回后持续存在。函数返回后,堆栈对象是否仍可从容器中检索?
void Test( std::vector<MyClass>& myvec )
{
MyClass m;
myvec.push_back(m);
}
在这种特殊情况下,m
将被复制构造为 的新实例MyClass
,该实例将归向量所有。所以可以从向量中检索一个不同但等效的实例,是的。MyClass
Is the stack object still retrievable from the container after the function returns?
是的,您myvec.push_back(m);
制作了 m 的副本,并且新副本由矢量管理。
但是,在您的函数返回后myvec
没有m
内部,因为您按值传递myvec
给 Test 函数,Test
函数会制作一个临时副本myvec
并复制m
到其中,在函数返回后myvec
释放临时副本。所以你的意思是通过引用传递myvec
给函数,如下所示:Test
public void Test(Vector<MyClass>& myvec){
MyClass m;
myvec.push_back(m);
}
基本假设:当您使用 时Vector
,您的真正意思是std::vector
。答案可能会随着设计足够不同的容器而改变。
只要你喜欢你通常应该的,并且在容器中存储对象(而不是指针),你就可以了,因为存储在容器中的通常是你传递的对象的副本。
在适当的情况下,容器中的对象可以从您传递的内容中移动构造,但效果基本相同 - 您最终会得到一个对象,其生命周期会一直持续到它从容器中移除(或容器被销毁, ETC。)
正如其他答案所指出的,m
被复制到向量中。也就是说,您的函数也按值接收向量(UPD:原始代码是这样,此后进行了编辑),这显然不是您想要的。
问题中的代码将在. 当方法退出时,原始将被破坏。MyClass
std::vector
m
Test
如果我们改变向量来存储指向我们的指针,MyClass
我们有两个可能的选择。
void Test( std::vector<MyClass*>& myvec )
{
// Allocates a new MyClass on the heap.
MyClass* pM = new MyClass();
myvec.push_back(pM);
// This variable will be allocated on the stack and cleaned up on method exit
MyClass dontDoThis;
myvec.push_back(&dontDoThis);
}
这个方法的最后myvec
有两个元素,myvec[0]
和myvec[1]
。
当存储指针容器时,必须分配对象,以便它在指针在容器中的时间长度内有效。在上面的示例中,pM
指针将在Test
方法退出后有效。这意味着myvec[0]
在方法退出后它将是一个有效的指针。
最初,一个指向dontDoThis
变量的有效指针将被添加到向量中,但是当方法退出时,dontDoThis
将调用析构函数,并且内存可能会用于存储其他数据。中的指针myvec
看起来不错,但任何实际使用它的尝试都会导致未定义的行为。在方法退出时,指针myvec[1]
可能看起来有效,但实际上它指向垃圾。
请注意,稍后,当myvec[0]
被更改或删除时,调用:
delete myvec[0]
以确保正确清理对象。否则会发生内存泄漏。
在解释了裸指针会发生什么之后,我强烈建议您使用智能指针,例如std::unique_ptr和std::shared_ptr
函数返回后,堆栈对象是否仍可从容器中检索?
仅当 MyClass 具有“gut”复制构造函数时。(深拷贝或共享其他资源的所有权等)
我的意思是,它可以被恢复,但它可能处于损坏状态