C++ 智能指针类的简单实现

C++ 智能指针类的简单实现,c++,copy-constructor,smart-pointers,C++,Copy Constructor,Smart Pointers,在《C++初级读物13.5.1》一书中,它使用一个使用计数类实现了一个智能指针类。其实施情况如下: 使用计数类 // private class for use by HasPtr only class U_Ptr { friend class HasPtr; int *ip; size_t use; U_Ptr(int *p): ip(p), use(1) { } ~U_Ptr() { delete ip; } }; 智能指针类 /* sm

在《C++初级读物13.5.1》一书中,它使用一个使用计数类实现了一个智能指针类。其实施情况如下:

  • 使用计数类

    // private class for use by HasPtr only
    class U_Ptr {
        friend class HasPtr;
        int *ip;
        size_t use;
        U_Ptr(int *p): ip(p), use(1) { }
        ~U_Ptr() { delete ip; }
    };
    
  • 智能指针类

    /* 
       smart pointer class: takes ownership of the dynamically allocated
       object to which it is bound
    
       User code must dynamically allocate an object to initialize a HasPtr
       and must not delete that object; the HasPtr class will delete it
    */
    class HasPtr {
    public:
        // HasPtr owns the pointer; p must have been dynamically allocated
        HasPtr(int *p, int i)
            : ptr(new U_Ptr(p)), val(i) { }
    
        // copy members and increment the use count
        HasPtr(const HasPtr &orig)
            : ptr(orig.ptr), val(orig.val) { ++ptr->use; }
    
        HasPtr& operator=(const HasPtr&);
    
        // if use count goes to zero, delete the U_Ptr object
        ~HasPtr() { if (--ptr->use == 0) delete ptr; } 
    
        friend ostream& operator<<(ostream&, const HasPtr&);
        // copy control and constructors as before
    
        // accessors must change to fetch value from U_Ptr object
        int *get_ptr() const { return ptr->ip; } 
        int get_int() const { return val; }
    
        // change the appropriate data member
        void set_ptr(int *p) { ptr->ip = p; }
        void set_int(int i) { val = i; }
    
        // return or change the value pointed to, so ok for const objects
        // Note: *ptr->ip is equivalent to *(ptr->ip)
        int get_ptr_val() const { return *ptr->ip; } 
        void set_ptr_val(int i) { *ptr->ip = i; }
    private:
        U_Ptr *ptr;        // points to use-counted U_Ptr class
        int val;
    };
    

    测试:我使用如下代码测试了上述
    智能指针类
    ,它似乎运行良好

    int main()
    {
        T t1;
        T t2(t1);
        T t3(t1);
        T t4;
        t4 = t1;
    
        return 0;
    }
    


    真正的问题:这个新的
    智能指针类
    ,只需一个
    int*countPtr
    就足够了吗?如果是,为什么还要像书中那样使用额外的
    use Count类呢?如果否,我会错过什么?

    原始实现的一个属性是在控制块对象中使用原始指针类型执行
    删除。这是部分类型擦除。无论复制了多少智能指针对象,但类型有所不同,原始控制块保持不变,通过原始指针类型执行
    delete

    但是,由于您显示的原始代码不是模板化的,因此必须假定它是早期的示例,随后是类似的模板化代码

    在基类层次结构中向上转换指针,就像复制智能指针一样,意味着只有静态已知的新类型具有虚拟析构函数时,新指针类型上的
    delete
    才有效


    例如,
    std::shared\u ptr
    也会通过原始指针类型删除(保证),除非明确提供执行其他操作的deleter functor。

    您的代码与本书中报告的标准代码等效。然而,在某些方面它是最糟糕的:

  • 您需要两个分配/解除分配而不是一个(两个整数而不是一个对象)。这可能会更慢,也更难管理

  • 每个对象中都有一个指针副本。所以:重复的信息,你应该保证保持有效

  • 对象较大(两个指针而不是一个指针)

  • 你只有一个积极的方面:

  • 对指针的访问是直接的,而不是间接的。这可能意味着使用您的实现对引用对象的访问会稍微快一点

  • 我的猜测是,作者——无论是有意识的还是潜意识的——意识到在现实世界的智能指针中有一个单独的类是有用的,例如:

    • 弱指针的计数(不确定您是否听说过它们-它们跟踪对象而不延长其生命周期,这样您可以稍后尝试将其转换为(正常)共享指针,但只有在至少有一个指向对象的共享指针使其保持活动状态时,它才起作用)

    • 使共享指针线程安全的互斥锁(尽管原子操作在可用时可能更好)

    • 调试信息(例如boost::shared#ptr有一个#ifdef以包含一个共享计数器id)

    • 虚拟调度表,由boost共享指针等使用,以调度到操作系统相应的代码(请参阅boost/smart_ptr/detail/sp_counted_base_*.hpp标头)

    我不知道这本书的内容,但也许他们会继续解释,在
    U_Ptr

    (2017年4月14日更新)

    我自己尝试了unique_ptr和shared_ptr,但有点惊讶地发现这些课程并没有让你的生活更轻松。我在一个API中有一个函数,函数将拾取
    对象*&
    -填写它(指针),然后需要删除该对象。可以使用c++11,但您需要为此添加额外的临时指针。(所以使用*ptr类并不会让我的生活更轻松)

    实现智能指针有多复杂

    通过快速浏览auto_ptr类实现,我已经快速编写了简单的智能点容器类,但是我注意到我需要支持引用同一对象指针的多个智能指针

    好的,那么编码引用计数会有多复杂呢?我通过,然后去了谷歌,找到了一篇关于它的有趣文章:

    不知何故,我倾向于同意那篇文章的作者和那篇文章中的评论,引用计数使生活变得更加复杂,但仍然试图坚持使用纯C也听起来有点愚蠢

    现在,我将在这里添加我自己的类的代码片段,如果您想获得最新版本,可以签入此svn存储库:

    下面是旧版本

    #pragma once
    
    //
    // If you're using multithreading, please make sure that two threads are not accessing 
    // SmartPtr<> pointers which are cross linked.
    //
    template <class T>
    class SmartPtr
    {
    public:
        SmartPtr() : ptr( nullptr ), next( nullptr )
        {
        }
    
        SmartPtr( T* pt ) : ptr( pt ), next( nullptr )
        {
        }
    
        SmartPtr( SmartPtr<T>& sp ) : ptr( nullptr ), next( nullptr )
        {
            operator=(sp);
        }
    
        ~SmartPtr()
        {
            release();
        }
    
        // Reference to pointer - assumed to be filled out by user.
        T*& refptr()
        {
            release();
            return ptr;
        }
    
        // Pointer itself, assumed to be used.
        T* get()
        {
            return ptr;
        }
    
        T* operator->() const
        {
            return ptr;
        }
    
        T* operator=( T* _ptr )
        {
            release();
            ptr = _ptr;
            return ptr;
        }
    
        SmartPtr<T>& operator=( SmartPtr<T>& sp )
        {
            release();
            ptr = sp.ptr;
    
            if ( ptr )      // If we have valid pointer, share ownership.
            {
    
                if( sp.next == nullptr )
                {
                    next = &sp;
                    sp.next = this;
                } else {
                    SmartPtr<T>* it = &sp;
    
                    while( it->next != &sp )
                        it = it->next;
    
                    next = &sp;
                    it->next = this;
                }
            }
    
            return *this;
        }
    
        void release()
        {
            if ( !ptr )
                return;
    
            // Shared ownership.
            if( next != nullptr )
            {
                // Remove myself from shared pointer list.
                SmartPtr<T>* it = next;
    
                while( it->next != this )
                    it = it->next;
    
                if( it == it->next->next )
                    it->next = nullptr;
                else
                    it->next = next;
    
                next = nullptr;
                ptr = nullptr;
                return;
            }
    
            // Single user.
            delete ptr;
            ptr = nullptr;
        }
    
        T* ptr;                 // pointer to object
        SmartPtr<T>* next;      // nullptr if pointer is not shared with anyone, 
                                // otherwise cyclic linked list of all SmartPtr referencing that pointer.
    };
    
    #pragma一次
    //
    //如果您使用的是多线程,请确保没有两个线程访问
    //交叉链接的SmartPtr指针。
    //
    模板
    类SmartPtr
    {
    公众:
    SmartPtr():ptr(nullptr),next(nullptr)
    {
    }
    智能ptr(T*pt):ptr(pt),next(nullptr)
    {
    }
    SmartPtr(SmartPtr&sp):ptr(nullptr),next(nullptr)
    {
    运算符=(sp);
    }
    ~SmartPtr()
    {
    释放();
    }
    //指针引用-假定由用户填写。
    T*&refptr()
    {
    释放();
    返回ptr;
    }
    //假定要使用的指针本身。
    T*get()
    {
    返回ptr;
    }
    T*运算符->()常量
    {
    返回ptr;
    }
    T*运算符=(T*_ptr)
    {
    释放();
    ptr=_ptr;
    返回ptr;
    }
    SmartPtr和操作员=(SmartPtr和sp)
    {
    释放();
    ptr=sp.ptr;
    if(ptr)//如果我们有有效的指针,则共享所有权。
    {
    如果(sp.next==nullptr)
    {
    下一步=&sp;
    sp.next=此;
    }否则{
    SmartPtr*it=&sp;
    while(it->next!=&sp)
    it=it->next;
    下一步=&sp;
    it->next=这个;
    }
    }
    返回
    
    #pragma once
    
    //
    // If you're using multithreading, please make sure that two threads are not accessing 
    // SmartPtr<> pointers which are cross linked.
    //
    template <class T>
    class SmartPtr
    {
    public:
        SmartPtr() : ptr( nullptr ), next( nullptr )
        {
        }
    
        SmartPtr( T* pt ) : ptr( pt ), next( nullptr )
        {
        }
    
        SmartPtr( SmartPtr<T>& sp ) : ptr( nullptr ), next( nullptr )
        {
            operator=(sp);
        }
    
        ~SmartPtr()
        {
            release();
        }
    
        // Reference to pointer - assumed to be filled out by user.
        T*& refptr()
        {
            release();
            return ptr;
        }
    
        // Pointer itself, assumed to be used.
        T* get()
        {
            return ptr;
        }
    
        T* operator->() const
        {
            return ptr;
        }
    
        T* operator=( T* _ptr )
        {
            release();
            ptr = _ptr;
            return ptr;
        }
    
        SmartPtr<T>& operator=( SmartPtr<T>& sp )
        {
            release();
            ptr = sp.ptr;
    
            if ( ptr )      // If we have valid pointer, share ownership.
            {
    
                if( sp.next == nullptr )
                {
                    next = &sp;
                    sp.next = this;
                } else {
                    SmartPtr<T>* it = &sp;
    
                    while( it->next != &sp )
                        it = it->next;
    
                    next = &sp;
                    it->next = this;
                }
            }
    
            return *this;
        }
    
        void release()
        {
            if ( !ptr )
                return;
    
            // Shared ownership.
            if( next != nullptr )
            {
                // Remove myself from shared pointer list.
                SmartPtr<T>* it = next;
    
                while( it->next != this )
                    it = it->next;
    
                if( it == it->next->next )
                    it->next = nullptr;
                else
                    it->next = next;
    
                next = nullptr;
                ptr = nullptr;
                return;
            }
    
            // Single user.
            delete ptr;
            ptr = nullptr;
        }
    
        T* ptr;                 // pointer to object
        SmartPtr<T>* next;      // nullptr if pointer is not shared with anyone, 
                                // otherwise cyclic linked list of all SmartPtr referencing that pointer.
    };