c++ - 什么时候从列表中弹出的对象被销毁?

标签 c++ stl

这可能是一个非常愚蠢/基本的问题,但我真的想不通。我会告诉你我的想法 - 如果/哪里我错了,请纠正我。

当我们使用 STL 容器存储原始指针时,我们必须注意清理它们:

std::list<animal*> alist;
animal *a = new animal();
alist.push_back(a);
...
animal *b = alist.front();
alist.pop_front();
//do stuff with b
delete b;

如果我们存储对象会发生什么?据我了解,如果装满对象的容器超出范围,则其中的所有对象都会被销毁。正确吗?

但是如果我们使用 std::list<T>.pop_front() 从容器中移除一个对象会怎样呢?例如?

std::list<animal> alist;
{
  animal ani();
  //ani is inserted at the end of the list (it IS ani rather than a copy 
  //since push_back accepts const T&)
  alist.push_back(ani);
} //nothing is deallocated/destroyed here
...
{
  animal b = alist.front(); //b is now a copy(?!) of the front element
                            //created via copy constructor
  alist.pop_front(); //the front element of the list is 
                     //destroyed/destructor is called 
  //do stuff with b
} //b goes out of scope

最佳答案

当你在容器中存储一些东西时,无论你传递什么都会被复制到容器1。您仍然拥有原始对象2;容器拥有它的对象拷贝。 push_back(例如)确实通过引用获取其参数。这意味着当您将要推送的对象传递到容器中时,不需要拷贝用作参数本身,但放入容器中的内容仍然是您告诉它推送的内容的拷贝。通过引用传递意味着只需要一个拷贝;如果它是按值传递的,(至少在 C++98/03 中)将导致两个 拷贝:一个拷贝从您的对象到函数参数,然后另一个拷贝从函数参数进入容器。通过引用传递允许将原始对象直接复制到容器中。

同样,当您从容器中获取对象时,您将获得容器中内容的拷贝。容器仍然有它的对象,而你有你的对象。其中每一个都有自己的生命周期。

当您从容器中删除或弹出一个对象时,该对象将从容器中移除并销毁——如果它是具有析构函数的对象,将调用析构函数来销毁它。

当容器本身被销毁时,容器中的对象也会被销毁。只要您的对象恰好被销毁,它就会被销毁——它来自容器这一事实对此没有影响。如果它是一个局部变量,它会在超出范围时被销毁。如果它是全局的,它将持续到时间结束(对于程序)。如果您从函数返回它并用于初始化引用,则将遵守延长其生命周期的正常规则。底线:到那时,它只是另一个对象,它的生命周期与以相同方式定义的任何其他对象一样。

当/如果您将指针(原始或智能)存储在容器中时,这可能会有点...模糊。以上所有内容实际上都是正确的,但是被复制/存储的对象是一个指针。除非你使用一些“知道”你正在存储指针的容器(例如,Boost ptr_vector),否则它只是处理一个指针,而“忽略”一个事实,即某个地方有一个指针指向的对象。


  1. 在 C++11 中,例如,您可以使用 emplace_back 在容器中就地构造一个对象,但同样的基本思想也适用——容器有一个它拥有的对象,而且您永远不会直接触摸。
  2. 在这里,我使用“对象”更像是一个非程序员的意思——只是指“某物”,不一定是一个类的实例。它甚至可能不是 C 使用这个词的意义上的“对象”——它可能是一个纯右值(例如,push_back(10))。

关于c++ - 什么时候从列表中弹出的对象被销毁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14361581/

相关文章:

c++ - 为什么 pair 在初始化时不需要类型

C++ A星实现--判断节点是否已经在未清项优先队列中

c++ - 使用 std::regex 分割行并丢弃空元素

c++ - boost::asio::ssl::context::add_verify_path

c++ - "Right"解除分配 std::vector 对象的方法

c++ - 将类型转换为 python

c++ - 解释两种几乎相同算法的性能差异

c++ - std::string::c_str() 和临时文件

c++ - 无法编译 std::reduce 调用,而 std::accumulate 调用编译相同的参数

c++ - 容器复杂度