为unique_ptr重新计数的替代方法

Alternatives to refcount for unique_ptr

本文关键字:方法 新计数 unique ptr      更新时间:2023-10-16

在下面的代码示例中,只要B的任何对象存在,结构体B中就应该存在一个结构体A的实例。

#include <memory>
#include <iostream>
#include <mutex>
struct A
{
    A() { std::cout << "A() called" << std::endl; }
    ~A() { std::cout << "~A() called" << std::endl; }
};
struct B
{
    B()
    {
        std::cout << "B() called" << std::endl; 
        std::lock_guard<std::mutex> guard(mtx);
        if( !refCount )
        {
            a.reset( new A ); 
        }
        ++refCount;
    }
    ~B()
    {
        std::cout << "~B() called" << std::endl;
        std::lock_guard<std::mutex> guard(mtx);
        --refCount;
        if( !refCount )
        {
            a.reset( ); 
        }
    }
    static std::unique_ptr<A> a;
    static std::mutex mtx;
    static int refCount;
};
std::unique_ptr<A> B::a;
int B::refCount(0);
std::mutex B::mtx;
int main()
{
    {
        B b1; //B::a should be created here
        B b2;
    } //B::a should be destroyed here
    B b3; // B::a should be recreated here
} //B::a should be destroyed again here

参见http://coliru.stacked-crooked.com/a/fea428254933ee5c

我的问题是:有没有一个替代的(线程安全的!)实现没有重新计数?这是否可能用std::shared_ptrstd::weak_ptr的结构来解决?

确保一个对象与B的任何对象一样存在的唯一方法是保持B对象的重新计数。这是判断是否存在任何活动的B对象,以及它们是否会在程序运行时被任意创建和销毁的唯一现实的方法。

std::shared_ptr在内部保留了自动跟踪的refcount。这可能是一个更好的主意,使用这些,而不是手动管理自己的回扣;这样,您就不必一丝不苟地实现所有的RAII构造器,或者重新发明轮子。

这是需要的解决方案:

#include <memory>
#include <iostream>
#include <mutex>
using std::shared_ptr;
using std::weak_ptr;
struct A
{
    A() { std::cout << "A() called" << std::endl; }
    ~A() { std::cout << "~A() called" << std::endl; }
};
struct B
{
    B()
    {   std::cout << "B() called" << std::endl;
        std::lock_guard<std::mutex> guard(mtx);
        if (!(ac =aw.lock()))
          aw =ac =shared_ptr<A>(new A);
    }
    ~B()
    {   std::cout << "~B() called" << std::endl;
    }
    shared_ptr<A> ac;
    static weak_ptr<A> aw;
    static std::mutex mtx;
};
weak_ptr<A> B::aw;
std::mutex B::mtx;
int main()
{
    {
        B b1; //B::a should be created here
        B b2;
    } //B::a should be destroyed here
    B b3; // B::a should be recreated here
} //B::a should be destroyed again here

生成与示例相同的输出:

B() called
A() called
B() called
~B() called
~B() called
~A() called
B() called
A() called
~B() called
~A() called