Допустим, этот класс Foo
:
struct Foo {
std::shared_ptr<int> data;
std::shared_ptr<std::vector<Foo>> foos;
};
Давайте создадим экземпляр Foo
и рассмотрим use_count()
его.data
переменная-член после добавления нескольких экземпляров в .foos
:
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';
}
output:
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 - Спасибо за любую помощь!