【发布时间】:2019-01-30 10:02:06
【问题描述】:
假设这个类Foo:
struct Foo {
std::shared_ptr<int> data;
std::shared_ptr<std::vector<Foo>> foos;
};
它有一个指向 int 的指针
它有一个指向该程序中将存在的所有实例的指针(因此这些实例之一 ==
*this)
让我们创建一个Foo 的实例,并在将一些实例添加到.foos 后查看其.data 成员变量的use_count():
int main() {
Foo foo;
foo.data = std::make_shared<int>(5);
foo.foos = std::make_shared<std::vector<Foo>>();
foo.foos->resize(8);
for (auto & f : *foo.foos) {
f.data = foo.data;
f.foos = foo.foos;
}
std::cout << "use count: " << foo.data.use_count() << '\n';
}
输出:
use count: 9
这很好 (1 foo + 8 .foos)。
不过好像main()返回时,还是会有 9 8个指针指向.data!这可以通过将foo 放入本地范围并让一个额外的指针指向.data 来随后观察这个指针use_count() 来证明:
int main() {
std::shared_ptr<int> ptr;
std::cout << "use count | before: " << ptr.use_count() << '\n';
{ //begin scope
Foo foo;
foo.data = std::make_shared<int>(5);
foo.foos = std::make_shared<std::vector<Foo>>();
foo.foos->resize(8);
for (auto & f : *foo.foos) {
f.data = foo.data;
f.foos = foo.foos;
}
ptr = foo.data;
std::cout << "use count | inside: " << ptr.use_count() << '\n';
} //end scope
std::cout << "use count | after: " << ptr.use_count() << '\n';
}
输出是:
use count | before: 0
use count | inside: 10
use count | after: 9
这不好。我希望use count | after 成为1,因为foo 并且它的所有成员都应该在范围结束时解构。好吧,foo 确实被解构了(否则 use_count | after 将是 10 而不是 9)但它的 .foos 向量指针没有被解构。而ptr 只是一个std::shared_ptr<int>,因此与struct Foo 毫无关系。所有这些都可以通过提供 struct Foo 一个析构函数来解决,该析构函数 reset()s 手动指向 .foos->data 指针:
#include <memory>
#include <iostream>
#include <vector>
struct Foo {
~Foo() {
for (auto& p : *foos) {
p.data.reset();
}
}
std::shared_ptr<int> data;
std::shared_ptr<std::vector<Foo>> foos;
};
int main() {
std::shared_ptr<int> ptr;
std::cout << "use count | before: " << ptr.use_count() << '\n';
{
Foo foo;
foo.data = std::make_shared<int>(5);
foo.foos = std::make_shared<std::vector<Foo>>();
foo.foos->resize(8);
for (auto & f : *foo.foos) {
f.data = foo.data;
f.foos = foo.foos;
}
ptr = foo.data;
std::cout << "use count | inside: " << ptr.use_count() << '\n';
}
std::cout << "use count | after: " << ptr.use_count() << '\n';
}
产生更好的输出:
use count | before: 0
use count | inside: 10
use count | after: 1
但是必须手动重置这些指针似乎很奇怪。为什么std::vector 或std::shared_ptr 不在这里自动执行此操作?它是一个错误吗?
我正在使用 Visual Studio Community 2017 版本 15.9.5 - 感谢您的帮助!
【问题讨论】:
-
不明白,在ent ptr 处仍然指向foos 数据并且使用count 为1?那么……有什么问题?
-
我明白了……对不起……
-
当程序超出 main() 范围时,指针将被释放。
-
没有错误,这是预期的行为。您必须手动重置那些嵌套的
Foos,因为您正在创建循环引用(向量中的Foos 对其所在的向量有一个 shared_ptr,从而使它们保持活动状态)并且 shared_ptr 并非旨在处理它。 -
离题:解构 == 销毁...
标签: c++ vector memory-management shared-ptr allocation