C++堆栈内存仍然有效吗?

3
如果我在堆栈上创建一个对象并将其推入列表中,那么对象失去作用域(在下面示例中的for循环之外),该对象是否仍然存在于列表中?如果列表仍然持有对象,那么数据现在是否无效/可能损坏?
请告诉我,并解释原因。
谢谢, jbu
class SomeObject{
public:
   AnotherObject x;
}

//And then...
void someMethod()
{
   std::list<SomeObject> my_list;
   for(int i = 0; i < SOME_NUMBER; i++)
   {
      SomeObject tmp;
      my_list.push_back(tmp);

      //after the for loop iteration, tmp loses scope
   }

   my_list.front(); //at this point will my_list be full of valid SomeObjects or will the SomeObjects no longer be valid, even if they still point to dirty data
}

编辑:如果它是一个std::list<SomeObject*> my_list而不是list...那么这种情况下是否无效?


你在底部编辑的评论很难理解。你想问什么? - swestrup
哦,是的,我的意思是问如果它看起来像这样,它是否仍然有效:std::list<SomeObject*> my_list; for() {SomeOjbect tmp; my_list.push_back(&tmp); } - jbu
如果你这样做,你会将tmp变量的地址推入列表中。每次迭代后,tmp都会被销毁,相应的列表条目现在指向一个已调用其析构函数并且指向可能被其他东西替换的堆栈内存的对象。如果你要将指针添加到此列表中,你需要确保对象的生命周期超过列表的生命周期。否则,你的指针可能引用垃圾。 - lhumongous
4个回答

6

标准容器会复制对象,因此在您的示例中列表仍然正常。


4

所有容器都会复制它们存储的内容。如果一个对象要在容器中使用,那么它必须是可复制构造和可赋值的。

因此,vectorlist等都会复制你的对象。


以下是更简短的示例:

struct foo {};
std::vector<foo> v;

v.push_back(foo()); 
// makes a copy of the temporary, which dies at the semicolon.

如果不进行复制,上述代码将会有问题。
以下代码是不可行的:
struct foo {};
std::vector<foo*> v;

{
    foo f;
    v.push_back(&f); // fine, but...
} // ...now f stops existing and...

v.front(); // ...points to a non-existent object.

2

是的,它是有效的。push_back会创建一个副本


如果是 std::list my_list; 而不是 list,那又怎样呢?在这种情况下会无效吗? - jbu
@jbu - 我不确定你在这里问什么。它是一个std::list。也许你可以给出一个代码示例来说明你的意思? - Tim
std::list<SomeObject*> my_list; for() { SomeOjbect tmp; my_list.push_back(&tmp);} - jbu
啊。不,那样做是不好的。在这种情况下,你的列表不是SomeObjects的列表,而只是指针的列表。在for循环内部,你在堆栈上创建了一个SomeObject,并将指针放入列表中。一旦退出该作用域,SomeObject就消失了,你的指针也无效了。 - Tim

0

对于所有的STL容器(包括列表、向量、映射等等),容器会将您添加到容器中的内容复制一份,只要您添加的内容不是指针或引用,就可以放心使用。

如果您自己编写容器,那么您必须小心处理操作,因为您可以编写一种存储引用的容器类型——这会给任何认为它像标准容器那样工作的人带来不好的惊喜。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接