1

在 C++ 中,如果您在堆栈上(在函数内)创建一个对象并将其插入到堆分配的容器中(该容器已被传递到函数中/在函数完成后存在),会发生什么?

堆栈对象具有本地范围,但它已插入其中的容器位于堆上,并且可以在函数(进行插入的位置)返回后持续存在。函数返回后,堆栈对象是否仍可从容器中检索?

void Test( std::vector<MyClass>& myvec )
{
    MyClass m;
    myvec.push_back(m);
}
4

6 回答 6

4

在这种特殊情况下,m将被复制构造为 的新实例MyClass,该实例将归向量所有。所以可以从向量中检索一个不同但等效的实例,是的。MyClass

于 2013-01-09T21:40:15.320 回答
2
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);
}
于 2013-01-09T21:41:02.570 回答
2

基本假设:当您使用 时Vector,您的真正意思是std::vector。答案可能会随着设计足够不同的容器而改变。

只要你喜欢你通常应该的,并且在容器中存储对象(而不是指针),你就可以了,因为存储在容器中的通常是你传递的对象的副本。

在适当的情况下,容器中的对象可以从您传递的内容中移动构造,但效果基本相同 - 您最终会得到一个对象,其生命周期会一直持续到它从容器中移除(或容器被销毁, ETC。)

于 2013-01-09T21:42:42.277 回答
0

正如其他答案所指出的,m被复制到向量中。也就是说,您的函数也按值接收向量(UPD:原始代码是这样,此后进行了编辑),这显然不是您想要的。

于 2013-01-09T21:41:51.433 回答
0

问题中的代码在. 当方法退出时,原始将被破坏。MyClassstd::vectormTest

如果我们改变向量来存储指向我们的指针,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_ptrstd::shared_ptr

于 2013-01-09T22:02:25.013 回答
0

函数返回后,堆栈对象是否仍可从容器中检索?

仅当 MyClass 具有“gut”复制构造函数时。(深拷贝或共享其他资源的所有权等)

我的意思是,它可以被恢复,但它可能处于损坏状态

于 2013-01-09T22:23:26.083 回答