这个std :: vector和std :: shared_ptr内存是否有漏洞?

Sta*_*nny 1 c++ memory-management allocation vector shared-ptr

假设这个类Foo:

struct Foo {
    std::shared_ptr<int> data;
    std::shared_ptr<std::vector<Foo>> foos;
};
Run Code Online (Sandbox Code Playgroud)
  • 它有一个指向int的指针

  • 它有一个指向此程序中将存在的所有实例的指针(因此其中一个实例== *this)

让我们创建一个实例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';    
}
Run Code Online (Sandbox Code Playgroud)

输出:

use count: 9
Run Code Online (Sandbox Code Playgroud)

哪个好(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';
}
Run Code Online (Sandbox Code Playgroud)

输出是:

use count | before: 0
use count | inside: 10
use count | after: 9
Run Code Online (Sandbox Code Playgroud)

哪个不好.我会excpect use count | after1因为foo其所有成员应在范围到底得的解构.好吧,foodefinetely得到解构(否则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';
}
Run Code Online (Sandbox Code Playgroud)

产生更好的输出:

use count | before: 0
use count | inside: 10
use count | after: 1
Run Code Online (Sandbox Code Playgroud)

但是人们必须手动重置这些指针似乎很奇怪.为什么std::vector还是std::shared_ptr这样做,自动在这里?这是一个错误吗?


我正在使用Visual Studio Community 2017版本15.9.5 - 感谢您的帮助!

Jar*_*d42 6

问题是你有一个循环引用.

foo被破坏,它减少引用计数的的shared_ptr,但那些没有达到零.

因此,即使std::shared_ptr<std::vector<Foo>>"无法访问",仍然有指针.(注意:垃圾收集器使用"辅助功能"来收集/释放指针).

打破循环的常用方法是使用std::weak_ptr.