c++ - 引用计数智能指针的赋值运算符

标签 c++ shared-ptr smart-pointers

尽管智能指针问题层出不穷,但我似乎又遇到了一个问题。我正在尝试实现一个引用计数的智能指针,但是当我在以下情况下尝试时,引用计数是错误的。评论是我认为应该是正确的引用计数。

Sptr<B> bp1(new B);       // obj1: ref count = 1
Sptr<B> bp2 = bp1;        // obj1: ref count = 2
bp2 = new B;              // obj1: ref count = 1, obj2: rec count = 1 **problem**

在我的实现中,我的 obj2 引用计数是 2,因为这段代码:

protected:
    void retain() { 
        ++(*_rc);
        std::cout << "retained, rc: " << *_rc << std::endl;
    }
    void release() {
        --(*_rc);
        std::cout << "released, rc: " << *_rc << std::endl;
        if (*_rc == 0) {
            std::cout << "rc = 0, deleting obj" << std::endl;
            delete _ptr;
            _ptr = 0;
            delete _rc;
            _rc = 0;
        }
    }

private:
    T *_ptr;
    int *_rc;

    // Delegate private copy constructor
    template <typename U>
    Sptr(const Sptr<U> *p) : _ptr(p->get()), _rc(p->rc()) {
        if (p->get() != 0) retain();
    }

    // Delegate private assignment operator
    template <typename U>
    Sptr<T> &operator=(const Sptr<U> *p) {
        if (_ptr != 0) release();
        _ptr = p->get();
        _rc = p->rc();
        if (_ptr != 0) retain();
        return *this;
    }

public:
    Sptr() : _ptr(0) {}
    template <typename U>
    Sptr(U *p) : _ptr(p) { _rc = new int(1); }

    // Normal and template copy constructors both delegate to private
    Sptr(const Sptr &o) : Sptr(&o) {
        std::cout << "non-templated copy ctor" << std::endl;
    }
    template <typename U>
    Sptr(const Sptr<U> &o) : Sptr(&o) {
        std::cout << "templated copy ctor" << std::endl;
    }


    // Normal and template assignment operator
    Sptr &operator=(const Sptr &o) {
        std::cout << "non-templated assignment operator" << std::endl;
        return operator=(&o);
    }
    template <typename U>
    Sptr<T> &operator=(const Sptr<U> &o) {
        std::cout << "templated assignment operator" << std::endl;          
        return operator=(&o);
    }
    // Assignment operator for assigning to void or 0
    void operator=(int) {
        if (_ptr != 0) release();
        _ptr = 0;
        _rc = 0;
    }

构造函数使用 ref count = 1 初始化,但在我的赋值运算符中,我保留了对象,使 ref count = 2。但在这种情况下它应该仅为 1,因为 bp2 = new B 只是一个指向该对象的指针。我查看了各种智能指针实现示例,但我似乎无法弄清楚它们如何处理我遇到的这种情况。

感谢您的宝贵时间!

最佳答案

无论如何,赋值运算符充满了小错误和不必要的复杂性。例如,当您分配 Sptr<T>对它自己来说,它会产生有趣的效果。大多数手动编写的赋值运算符应该如下所示:

T& T::operator= (T const& other) {
    T(other).swap(*this);
    return *this;
}

...或者

T& T::operator= (T other) {
    other.swap(*this);
    return *this;
}

一旦有状态分配器进入游戏,事情就会发生一些变化,但我们可以在这里忽略这个细节。主要思想是利用为复制构造函数和析构函数所做的现有工作。请注意,如果右侧不是 T,此方法也适用,即,您仍然可以利用相应的构造函数、析构函数和 swap() .无论如何,唯一可能的额外工作是可取的,并且实现起来微不足道:swap()成员。在您的情况下,这也非常简单:

template <typename T>
void Sptr<T>::swap(Sptr<T>& other) {
    std::swap(this->_ptr, other._ptr);
    std::swap(this->_rc,  other._rc);
}

请注意您的赋值运算符采用 int : 这是一个非常糟糕的主意!要重置指针,您最好使用 reset()。方法。在 C++ 2011 中,您可以合理地使用一个采用 std::nullptr_t 的方法。不过,为了这个目的。

关于c++ - 引用计数智能指针的赋值运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13435042/

相关文章:

c++ - 有没有一种方法可以将std::make_unique与指定给函数的不同类一起传递

c++ - 存储成员函数模板实例时出错

c++ - Eclipse CDT 将 "normal folder"转换为 "source folder",反之亦然

c++ - 如何从用户代码中移动鼠标光标?

c++ - 为什么 <const char*> 和 <const char[]> 有非常不同的内存或指针行为?

c++ - 如何在构造函数的初始化列表中初始化共享指针?

c++ - 存储抽象成员,保持接口(interface)简单

c++ - 当 C++11 不是一个选项时,不共享所有权的智能指针

C++——指针传递问题

c++ - 我可以通过引用函数来传递 auto_ptr 吗?