C ++:C ++如何知道破坏容器内的智能指针?

问题描述

在C ++编程语言中,有以下示例(部分 3.2.4)。

unique_ptr<Shape> read_shape(istream& is);

void user()
{
    vector<unique_ptr<Shape>> v;
    while (cin)
        v.push_back(read_shape(cin));
    draw_all(v);
    // call draw() for each element
    rotate_all(v,45);
    // call rotate(45) for each element
} // all Shapes implicitly destroyed

Stroustrup试图通过使用unique_ptrs来说明这一点, 不必手动遍历向量并删除所有 形状。我很难理解为什么这是真的。

我理解智能指针的方式是,如果智能指针sptr为 分配在堆栈上,类似

std::unique_ptr<Shape> sptr(new Shape());

您无需在函数结尾处调用delete。然而, 从上面的例子中我可以看出,那些智能指针不是 在堆栈上,它们被放在v的数据数组中,该数组位于 堆。

解决方法

unique_ptr是在堆栈上还是在堆上并不重要。重要的是,它的析构函数运行时,它将自动在目标指针上调用delete

vector超出范围时,向量的destructor运行。那会破坏所有包含的元素(在进程中调用它们的析构函数),然后释放其堆缓冲区。

,

这是析构函数的用途。您看不到破坏唯一指针的“手动循环”,因为该循环在向量的析构函数之内。所有容器都破坏了它们的元素。

,

运行std::vector的析构函数时,它将为它包含的每个对象调用析构函数。 std::unique_ptr的析构函数在其包装的指针上调用delete / delete[],因此分配的所有内存都将被正确清除。

,

是的,如果在堆上创建某些内容,则必须自己删除它。与自动变量(即使标准并没有强制要求存在堆栈的自动变量)不同,这些对象的生存期(作用域)可以跨函数返回边界继续。

但是,这里的 vector 不在堆上-它实际上是一个自动变量,无疑会将其 some 信息存储在堆上(保存向量的数组元素),但变量本身不是。

这意味着,当它从user()退出时超出范围时,将调用析构函数。该析构函数足够聪明,可以为向量本身释放特定于堆的内容,为向量中的每个元素调用析构函数。

当然,销毁这些元素中的每一个都可能导致调用其他析构函数。如果要破坏的那些元素之一是智能指针,则 it 将知道它需要释放其对基础指针的保留,方法是释放它或减少计数以表示它不再对它。

,

std::unique_ptr本身被破坏或重置时,它将在其所在的对象/数组上调用deletedelete[](或您指定的自定义deleter)当前持有指向的指针。

如果std::unique_ptr是在自动内存(例如堆栈)中创建的,则超出范围时将被破坏。

如果std::unique_ptr是在 dynamic 内存(例如堆)中创建的,则在其上调用delete时会破坏它。

一个容器拥有它存储的元素。它知道其元素是否为定义析构函数的类型,如果是,则它将在需要时在每个元素上调用该析构函数,例如,从容器中删除单个元素时,或者当容器本身被解构或清除时

因此,如果您有一个std::unique_ptr元素的容器,则它们将在适当时为您破坏,从而破坏它们所指向的内容。