问题描述
在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
本身被破坏或重置时,它将在其所在的对象/数组上调用delete
或delete[]
(或您指定的自定义deleter
)当前持有指向的指针。
如果std::unique_ptr
是在自动内存(例如堆栈)中创建的,则超出范围时将被破坏。
如果std::unique_ptr
是在 dynamic 内存(例如堆)中创建的,则在其上调用delete
时会破坏它。
一个容器拥有它存储的元素。它知道其元素是否为定义析构函数的类型,如果是,则它将在需要时在每个元素上调用该析构函数,例如,从容器中删除单个元素时,或者当容器本身被解构或清除时
因此,如果您有一个std::unique_ptr
元素的容器,则它们将在适当时为您破坏,从而破坏它们所指向的内容。