智能指针

C++里面的智能指针包括auto_ptr, shared_ptr, unique_ptr, weak_ptr四种。
auto_ptr

template<class _Ty>
    class auto_ptr
        {   // wrap an object pointer to ensure destruction
public:
    typedef auto_ptr<_Ty> _Myt;
    typedef _Ty element_type;

    explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
        : _Myptr(_Ptr)
        {   // construct from object pointer
        }

    auto_ptr(_Myt& _Right) _THROW0()
        : _Myptr(_Right.release())
        {   // construct by assuming pointer from _Right auto_ptr
        }

    auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
        {   // construct by assuming pointer from _Right auto_ptr_ref
        _Ty *_Ptr = _Right._Ref;
        _Right._Ref = 0;    // release old
        _Myptr = _Ptr;  // reset this
        }

    template<class _Other>
        operator auto_ptr<_Other>() _THROW0()
        {   // convert to compatible auto_ptr
        return (auto_ptr<_Other>(*this));
        }

    template<class _Other>
        operator auto_ptr_ref<_Other>() _THROW0()
        {   // convert to compatible auto_ptr_ref
        _Other *_Cvtptr = _Myptr;   // test implicit conversion
        auto_ptr_ref<_Other> _Ans(_Cvtptr);
        _Myptr = 0; // pass ownership to auto_ptr_ref
        return (_Ans);
        }

    template<class _Other>
        _Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
        {   // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
        }

    template<class _Other>
        auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
        : _Myptr(_Right.release())
        {   // construct by assuming pointer from _Right
        }

    _Myt& operator=(_Myt& _Right) _THROW0()
        {   // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
        }

    _Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()
        {   // assign compatible _Right._Ref (assume pointer)
        _Ty *_Ptr = _Right._Ref;
        _Right._Ref = 0;    // release old
        reset(_Ptr);    // set new
        return (*this);
        }

    ~auto_ptr() _NOEXCEPT
        {   // destroy the object
        delete _Myptr;
        }

    _Ty& operator*() const _THROW0()
        {   // return designated value
 #if _ITERATOR_DEBUG_LEVEL == 2
        if (_Myptr == 0)
            _DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

        return (*get());
        }

    _Ty *operator->() const _THROW0()
        {   // return pointer to class object
 #if _ITERATOR_DEBUG_LEVEL == 2
        if (_Myptr == 0)
            _DEBUG_ERROR("auto_ptr not dereferencable");
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

        return (get());
        }

    _Ty *get() const _THROW0()
        {   // return wrapped pointer
        return (_Myptr);
        }

    _Ty *release() _THROW0()
        {   // return wrapped pointer and give up ownership
        _Ty *_Tmp = _Myptr;
        _Myptr = 0;
        return (_Tmp);
        }

    void reset(_Ty *_Ptr = 0)
        {   // destroy designated object and store new pointer
        if (_Ptr != _Myptr)
            delete _Myptr;
        _Myptr = _Ptr;
        }

private:
    _Ty *_Myptr;    // the wrapped object pointer
    };

auto_ptr的拷贝构造函数, 拷贝赋值函数用得都是非const的引用类型, 我们可以修改源对象。例如:

 std::auto_ptr<Simple> my_memory(new Simple(1));
    std::auto_ptr<Simple> my_memory2;   // 创建一个新的 my_memory2 对象
    my_memory2 = my_memory;             // 复制旧的 my_memory 给 my_memory2
    my_memory2->PrintSomething();       // 输出信息,复制成功
    my_memory->PrintSomething();        // 崩溃

当使用=号赋值操作时, my_memory2完全剥夺了my_memory的内存管理所有权, 导致my_memory悬空, 最后使用时崩溃。
std::auto_ptr 的 release() 函数只是让出内存所有权,这显然也不符合 C++ 编程思想。
总结:std::auto_ptr 可用来管理单个对象的对内存,但是,请注意如下几点:
(1) 尽量不要使用“operator=”。如果使用了,请不要再使用先前对象。
(2) 记住 release() 函数不会释放对象,仅仅归还所有权。
(3) std::auto_ptr 最好不要当成参数传递(读者可以自行写代码确定为什么不能)。
(4) 由于 std::auto_ptr 的“operator=”问题,有其管理的对象不能放入 std::vector 等容器中。


unique_ptr

template<class _Ty,
    class _Dx>  // = default_delete<_Ty>
    class unique_ptr
        : private _Unique_ptr_base<_Ty, _Dx,
            is_empty<_Dx>::value
                || is_same<default_delete<_Ty>, _Dx>::value>
    {   // non-copyable pointer to an object
public:
    typedef unique_ptr<_Ty, _Dx> _Myt;
    typedef _Unique_ptr_base<_Ty, _Dx,
        is_empty<_Dx>::value
            || is_same<default_delete<_Ty>, _Dx>::value> _Mybase;
    typedef typename _Mybase::pointer pointer;
    typedef _Ty element_type;
    typedef _Dx deleter_type;

    using _Mybase::get_deleter;

    unique_ptr() _NOEXCEPT
        : _Mybase(pointer())
        {   // default construct
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    unique_ptr(nullptr_t) _NOEXCEPT
        : _Mybase(pointer())
        {   // null pointer construct
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    _Myt& operator=(nullptr_t) _NOEXCEPT
        {   // assign a null pointer
        reset();
        return (*this);
        }

    explicit unique_ptr(pointer _Ptr) _NOEXCEPT
        : _Mybase(_Ptr)
        {   // construct with pointer
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    unique_ptr(pointer _Ptr,
        typename _If<is_reference<_Dx>::value, _Dx,
            const typename remove_reference<_Dx>::type&>::type _Dt) _NOEXCEPT
        : _Mybase(_Ptr, _Dt)
        {   // construct with pointer and (maybe const) deleter&
        }

    unique_ptr(pointer _Ptr,
        typename remove_reference<_Dx>::type&& _Dt) _NOEXCEPT
        : _Mybase(_Ptr, _STD move(_Dt))
        {   // construct by moving deleter
        static_assert(!is_reference<_Dx>::value,
            "unique_ptr constructed with reference to rvalue deleter");
        }

    unique_ptr(unique_ptr&& _Right) _NOEXCEPT
        : _Mybase(_Right.release(),
            _STD forward<_Dx>(_Right.get_deleter()))
        {   // construct by moving _Right
        }

    template<class _Ty2,
        class _Dx2,
        class = typename enable_if<!is_array<_Ty2>::value
            && is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer,
                pointer>::value
            && ((is_reference<_Dx>::value && is_same<_Dx, _Dx2>::value)
                || (!is_reference<_Dx>::value
                    && is_convertible<_Dx2, _Dx>::value)),
            void>::type>
        unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
            : _Mybase(_Right.release(),
                _STD forward<_Dx2>(_Right.get_deleter()))
        {   // construct by moving _Right
        }

    template<class _Ty2,
        class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value
            && is_same<_Dx, default_delete<_Ty> >::value,
            void>::type>
        unique_ptr(auto_ptr<_Ty2>&& _Right) _NOEXCEPT
            : _Mybase(_Right.release())
        {   // construct by moving _Right
        }

    template<class _Ty2,
        class _Dx2>
        typename enable_if<!is_array<_Ty2>::value
            && is_convertible<typename unique_ptr<_Ty2, _Dx2>::pointer,
                pointer>::value,
            _Myt&>::type
        operator=(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
        {   // assign by moving _Right
        reset(_Right.release());
        this->get_deleter() = _STD forward<_Dx2>(_Right.get_deleter());
        return (*this);
        }

    _Myt& operator=(_Myt&& _Right) _NOEXCEPT
        {   // assign by moving _Right
        if (this != &_Right)
            {   // different, do the move
            reset(_Right.release());
            this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
            }
        return (*this);
        }

    void swap(_Myt& _Right) _NOEXCEPT
        {   // swap elements
        _Swap_adl(this->_Myptr, _Right._Myptr);
        _Swap_adl(this->get_deleter(),
            _Right.get_deleter());
        }

    ~unique_ptr() _NOEXCEPT
        {   // destroy the object
        if (this->_Myptr != pointer())
            this->get_deleter()(this->_Myptr);
        }

    typename add_reference<_Ty>::type operator*() const
        {   // return reference to object
        return (*this->_Myptr);
        }

    pointer operator->() const _NOEXCEPT
        {   // return pointer to class object
        return (_STD pointer_traits<pointer>::pointer_to(**this));
        }

    pointer get() const _NOEXCEPT
        {   // return pointer to object
        return (this->_Myptr);
        }

    explicit operator bool() const _NOEXCEPT
        {   // test for non-null pointer
        return (this->_Myptr != pointer());
        }

    pointer release() _NOEXCEPT
        {   // yield ownership of pointer
        pointer _Ans = this->_Myptr;
        this->_Myptr = pointer();
        return (_Ans);
        }

    void reset(pointer _Ptr = pointer()) _NOEXCEPT
        {   // establish new pointer
        pointer _Old = this->_Myptr;
        this->_Myptr = _Ptr;
        if (_Old != pointer())
            this->get_deleter()(_Old);
        }

    unique_ptr(const _Myt&) = delete;
    _Myt& operator=(const _Myt&) = delete;
    };

unique_ptr禁止了拷贝和赋值操作, 一个unique_ptr拥有它指向的对象。
release函数返回unique_ptr当前保存的指针并将其置为空,reset函数接受一个可选的指针参数, 令unique_ptr重新指向给定的指针。
shared_ptr

template<class _Ty>
    class shared_ptr
        : public _Ptr_base<_Ty>
    {   // class for reference counted resource management
public:
    typedef shared_ptr<_Ty> _Myt;
    typedef _Ptr_base<_Ty> _Mybase;

    shared_ptr() _NOEXCEPT
        {   // construct empty shared_ptr
        }

    template<class _Ux>
        explicit shared_ptr(_Ux *_Px)
        {   // construct shared_ptr object that owns _Px
        _Resetp(_Px);
        }

    template<class _Ux,
        class _Dx>
        shared_ptr(_Ux *_Px, _Dx _Dt)
        {   // construct with _Px, deleter
        _Resetp(_Px, _Dt);
        }

    shared_ptr(nullptr_t)
        {   // construct empty shared_ptr
        }

    template<class _Dx>
        shared_ptr(nullptr_t, _Dx _Dt)
        {   // construct with nullptr, deleter
        _Resetp((_Ty *)0, _Dt);
        }

    template<class _Dx,
        class _Alloc>
        shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
        {   // construct with nullptr, deleter, allocator
        _Resetp((_Ty *)0, _Dt, _Ax);
        }

    template<class _Ux,
        class _Dx,
        class _Alloc>
        shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // construct with _Px, deleter, allocator
        _Resetp(_Px, _Dt, _Ax);
        }

    template<class _Ty2>
        shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
        {   // construct shared_ptr object that aliases _Right
        this->_Reset(_Px, _Right);
        }

    shared_ptr(const _Myt& _Other) _NOEXCEPT
        {   // construct shared_ptr object that owns same resource as _Other
        this->_Reset(_Other);
        }

    template<class _Ty2,
        class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void>::type>
        shared_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct shared_ptr object that owns same resource as _Other
        this->_Reset(_Other);
        }

    template<class _Ty2>
        explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
            bool _Throw = true)
        {   // construct shared_ptr object that owns resource *_Other
        this->_Reset(_Other, _Throw);
        }

    template<class _Ty2>
        shared_ptr(auto_ptr<_Ty2>&& _Other)
        {   // construct shared_ptr object that owns *_Other.get()
        this->_Reset(_STD move(_Other));
        }

    template<class _Ty2>
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
        {   // construct shared_ptr object for static_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    template<class _Ty2>
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
        {   // construct shared_ptr object for const_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    template<class _Ty2>
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag)
        {   // construct shared_ptr object for dynamic_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    shared_ptr(_Myt&& _Right) _NOEXCEPT
        : _Mybase(_STD forward<_Myt>(_Right))
        {   // construct shared_ptr object that takes resource from _Right
        }

    template<class _Ty2,
        class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void>::type>
        shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
        : _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
        {   // construct shared_ptr object that takes resource from _Right
        }

    template<class _Ux,
        class _Dx>
        shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
        {   // construct from unique_ptr
        _Resetp(_Right.release(), _Right.get_deleter());
        }

    template<class _Ux,
        class _Dx>
        _Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right)
        {   // move from unique_ptr
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    _Myt& operator=(_Myt&& _Right) _NOEXCEPT
        {   // construct shared_ptr object that takes resource from _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    template<class _Ty2>
        _Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
        {   // construct shared_ptr object that takes resource from _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    ~shared_ptr() _NOEXCEPT
        {   // release resource
        this->_Decref();
        }

    _Myt& operator=(const _Myt& _Right) _NOEXCEPT
        {   // assign shared ownership of resource owned by _Right
        shared_ptr(_Right).swap(*this);
        return (*this);
        }

    template<class _Ty2>
        _Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign shared ownership of resource owned by _Right
        shared_ptr(_Right).swap(*this);
        return (*this);
        }

    template<class _Ty2>
        _Myt& operator=(auto_ptr<_Ty2>&& _Right)
        {   // assign ownership of resource pointed to by _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    void reset() _NOEXCEPT
        {   // release resource and convert to empty shared_ptr object
        shared_ptr().swap(*this);
        }

    template<class _Ux>
        void reset(_Ux *_Px)
        {   // release, take ownership of _Px
        shared_ptr(_Px).swap(*this);
        }

    template<class _Ux,
        class _Dx>
        void reset(_Ux *_Px, _Dx _Dt)
        {   // release, take ownership of _Px, with deleter _Dt
        shared_ptr(_Px, _Dt).swap(*this);
        }

    template<class _Ux,
        class _Dx,
        class _Alloc>
        void reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // release, take ownership of _Px, with deleter _Dt, allocator _Ax
        shared_ptr(_Px, _Dt, _Ax).swap(*this);
        }

    void swap(_Myt& _Other) _NOEXCEPT
        {   // swap pointers
        this->_Swap(_Other);
        }

    _Ty *get() const _NOEXCEPT
        {   // return pointer to resource
        return (this->_Get());
        }

    typename add_reference<_Ty>::type operator*() const _NOEXCEPT
        {   // return reference to resource
        return (*this->_Get());
        }

    _Ty *operator->() const _NOEXCEPT
        {   // return pointer to resource
        return (this->_Get());
        }

    bool unique() const _NOEXCEPT
        {   // return true if no other shared_ptr object owns this resource
        return (this->use_count() == 1);
        }

    explicit operator bool() const _NOEXCEPT
        {   // test if shared_ptr object owns no resource
        return (this->_Get() != 0);
        }

private:
    template<class _Ux>
        void _Resetp(_Ux *_Px)
        {   // release, take ownership of _Px
        _TRY_BEGIN  // allocate control block and reset
        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));
        _CATCH_ALL  // allocation failed, delete resource
        delete _Px;
        _RERAISE;
        _CATCH_END
        }

    template<class _Ux,
        class _Dx>
        void _Resetp(_Ux *_Px, _Dx _Dt)
        {   // release, take ownership of _Px, deleter _Dt
        _TRY_BEGIN  // allocate control block and reset
        _Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
        _CATCH_ALL  // allocation failed, delete resource
        _Dt(_Px);
        _RERAISE;
        _CATCH_END
        }

    template<class _Ux,
        class _Dx,
        class _Alloc>
        void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // release, take ownership of _Px, deleter _Dt, allocator _Ax
        typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
        typename _Alloc::template rebind<_Refd>::other _Al = _Ax;

        _TRY_BEGIN  // allocate control block and reset
        _Refd *_Ptr = _Al.allocate(1);
        ::new (_Ptr) _Refd(_Px, _Dt, _Al);
        _Resetp0(_Px, _Ptr);
        _CATCH_ALL  // allocation failed, delete resource
        _Dt(_Px);
        _RERAISE;
        _CATCH_END
        }

public:
    template<class _Ux>
        void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
        {   // release resource and take ownership of _Px
        this->_Reset0(_Px, _Rx);
        _Enable_shared(_Px, _Rx);
        }
    };

weak_ptr

    // TEMPLATE CLASS weak_ptr
template<class _Ty>
    class weak_ptr
        : public _Ptr_base<_Ty>
    {   // class for pointer to reference counted resource
public:
    weak_ptr() _NOEXCEPT
        {   // construct empty weak_ptr object
        }

    weak_ptr(const weak_ptr& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource pointed to by _Other
        this->_Resetw(_Other);
        }

    template<class _Ty2,
        class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void>::type>
        weak_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource owned by _Other
        this->_Resetw(_Other);
        }

    template<class _Ty2,
        class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
            void>::type>
        weak_ptr(const weak_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource pointed to by _Other
        this->_Resetw(_Other.lock());
        }

    ~weak_ptr() _NOEXCEPT
        {   // release resource
        this->_Decwref();
        }

    weak_ptr& operator=(const weak_ptr& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right);
        return (*this);
        }

    template<class _Ty2>
        weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right.lock());
        return (*this);
        }
    template<class _Ty2>
        weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right);
        return (*this);
        }

    void reset() _NOEXCEPT
        {   // release resource, convert to null weak_ptr object
        this->_Resetw();
        }

    void swap(weak_ptr& _Other) _NOEXCEPT
        {   // swap pointers
        this->_Swap(_Other);
        }

    bool expired() const _NOEXCEPT
        {   // return true if resource no longer exists
        return (this->_Expired());
        }

    shared_ptr<_Ty> lock() const _NOEXCEPT
        {   // convert to shared_ptr
        return (shared_ptr<_Ty>(*this, false));
        }
    };

weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。weak_ptr没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这是它弱的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。

weak_ptr用于解决”引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器。weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。weak_ptr提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空”shared_ptr)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,188评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,464评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,562评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,893评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,917评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,708评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,430评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,342评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,801评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,976评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,115评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,804评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,458评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,008评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,135评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,365评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,055评论 2 355

推荐阅读更多精彩内容

  • 原作者:Babu_Abdulsalam 本文翻译自CodeProject,转载请注明出处。 引入### Ooops...
    卡巴拉的树阅读 30,100评论 13 74
  • 1. 什么是智能指针? 智能指针是行为类似于指针的类对象,但这种对象还有其他功能。 2. 为什么设计智能指针? 引...
    MinoyJet阅读 638评论 0 1
  • C++ 智能指针详解 一、简介由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 de...
    yangqi916阅读 1,370评论 0 2
  • C++智能指针 原文链接:http://blog.csdn.net/xiaohu2022/article/deta...
    小白将阅读 6,864评论 2 21
  • 导读## 最近在补看《C++ Primer Plus》第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰...
    小敏纸阅读 2,004评论 1 12