C++11 智能指针

一、auto_ptr(C++98内容,C++11开始被舍弃)

先上源码(位于memory.h中):

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

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

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

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

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

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

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

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

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

auto_ptr& operator=(auto_ptr_ref<_Ty> _Right) noexcept
{	// 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;
}

_NODISCARD _Ty& operator*() const noexcept
{	// return designated value
    #if _ITERATOR_DEBUG_LEVEL == 2
    _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
    #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

    return (*get());
}

_NODISCARD _Ty * operator->() const noexcept
{	// return pointer to class object
    #if _ITERATOR_DEBUG_LEVEL == 2
    _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
    #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

    return (get());
}

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

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

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

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

1.接口简介

接口

作用

auto_ptr(_Ty * _Ptr)

构造函数。创建一个auto_ptr对象,并管理指针_Ptr的释放

~auto_ptr()

析构函数。释放管理的指针_Myptr

operator*()

重载*操作符获取当前 auto_ptr 指针指向的数据。

operator->()

重载 ->操作符,当智能指针指向非基础类型时,通过 -> 运算符可以获取其内部的指定成员。

operator=()

重载 = 操作符,从而将一个相同类型指针的auto_ptr赋值给当前auto_ptr,当前auto_ptr获得指针的所有权。

get()

获取当前 auto_ptr 指针内部包含的普通指针。

release()

释放当前 auto_ptr 指针对所指堆内存的所有权(注意不是释放内存),并返回指针。

reset(p)

如果p不等于当前auto_ptr管理的指针,则释放当前管理的指针,并开始管理;否则直接赋值。

2.成员

可以看到auto_ptr是一个类模板,整体结构比较简单,只有一个成员(被包装的指针):

_Ty * _Myptr;

3.构造/析构

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

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

构造函数负责将参数_Ptr给成员_Myptr初始化。

析构函数负责释放成员_Myptr。

4.操作接口

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

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

auto_ptr提供release和reset两个接口

release会将当前管理的内存返回,并将_Myptr置空。注意不是释放当前内存

reset则根据传入的参数决定行为,如果传入的指针不是当前保存的指针,则会释放当前指向的内存,并重新赋值

5.访问接口


_NODISCARD _Ty& operator*() const noexcept
{	// return designated value
    #if _ITERATOR_DEBUG_LEVEL == 2
    _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
    #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

    return (*get());
}

_NODISCARD _Ty * operator->() const noexcept
{	// return pointer to class object
    #if _ITERATOR_DEBUG_LEVEL == 2
    _STL_VERIFY(_Myptr, "auto_ptr not dereferencable");
    #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

    return (get());
}

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

重载*操作符,返回指针指向的数据

重载->操作符,返回顶层指针,可以通过此指针访问原始指针的内容,但是不能修改该指针的指向。

get()函数,与重载->操作符一致。(源码可以看到就是调用的get()函数)

6.拷贝/赋值

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

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

auto_ptr重载了拷贝和赋值函数,以此实现所有权的变化。

两者主要操作都是调用了release函数,释放被拷贝智能指针的所有权并置空,将其转到当前智能指针下。


using namespace std;
int main()
{
	//构造
	auto_ptr<int> iptr(new int(10));
	auto_ptr<string> sptr(new string("123"));

	//release之后auto_ptr中的指针置空
	int *ival = iptr.release();
	string *sval = sptr.release();
	cout << *ival <<" "<< sval->c_str() << endl;	//10 "123"
	//get获取原始指针
	int *ival2 = iptr.get();
	string *sval2 = sptr.get();
	cout << (ival2 ==nullptr) << " " << (sval2==nullptr) << endl;	//true
	//reset将参数赋值给auto_ptr中管理的指针
	iptr.reset(ival);
	sptr.reset(sval);
	cout << *ival << " " << sval->c_str() << endl;	//10 "123"
}

7.auto_ptr的问题

  • 因为指针所有权会随着赋值、拷贝等操作变化,导致原有的auto_ptr失效,因此很容易引起崩溃。这就使得在一些很常见的场景下出现问题:
using namespace std;
void test(auto_ptr<int> val) {

}

int main()
{
	auto_ptr<int> iptr(new int(10));
	test(iptr);	//iptr对指针的所有权被释放,后续访问崩溃
	cout << *iptr << endl;	//10 "123"
}

这里的根本原因其实就是忽略了,指针拷贝的场景。

  • 由于没有重载bool操作符,因此对指针是否失效智能通过get函数返回后比较,十分不便。

二、unique_ptr

1.简介

以独占的方式管理内存,为了避免auto_ptr的拷贝问题,一方面删除了拷贝构造和拷贝赋值

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

另一方面提供了移动拷贝构造和移动赋值


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

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

以适应移动语义:

unique_ptr<int>  test()
{
	return unique_ptr<int>(new int(10));
}

int main()
{
	//构造
	unique_ptr<int> iptr(new int(11));
	unique_ptr<int> iptr2(std::move(iptr));

	unique_ptr<int> iptr3 = test();			//返回值时的移动语义
	unique_ptr<int> iptr4 = std::move(iptr3);	//通过move调用移动语义

2.接口简介

成员函数名

功 能

operator*()

获取当前 unique_ptr 指针指向的数据。

operator->()

重载 -> 运算符,当智能指针自定义类型时,通过 -> 运算符可以获取其内部的指定成员。

operator =()

重载了 = 运算符,从而可以将 nullptr 或者一个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。

operator []()

重载了 [] 运算符,当 unique_ptr 指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。

get()

获取当前 unique_ptr 指针内部包含的普通指针。

get_deleter()

获取当前 unique_ptr 指针的删除器。

operator bool()

重载bool运算符,判断unique_ptr的指针是否为空。

release()

释放当前 unique_ptr 指针对所指堆内存的所有权,但该存储空间并不会被销毁。

reset(p)

其中 p 表示一个普通指针,如果 p 为 nullptr,则当前 unique_ptr 也变成空指针;反之,则该函数会释放当前 unique_ptr 指针指向的堆内存(如果有),然后获取 p 所指堆内存的所有权(p 为 nullptr)。

swap(x)

交换当前 unique_ptr 指针和同类型的 x 指针。

整体接口与auto_ptr功能类似。

3.类设计(vs2017版)

UML类图

unique_ptr

截取unique_ptr类模板部分源码:

// CLASS TEMPLATE unique_ptr SCALAR
template<class _Ty,
class _Dx>	// = default_delete<_Ty>
class unique_ptr
: public _Unique_ptr_base<_Ty, _Dx>
{	// non-copyable pointer to an object
public:
//...
}
  1. 可以看到unique_ptr为类模板,接收两个类模板参数_Ty和_Dx,其中:
  • _Ty表示所需管理的指针类型
  • _Dx表示释放指针内存的删除器,默认采用default_delete<_Ty>方式,一般可以不传。
  1. 此外,unique_ptr中没有成员变量,而是存储与其基类_Unique_ptr_base中

default_delete<_Ty>

default_delete<_Ty>作为默认的删除器,源码如下:

template<class _Ty>
struct default_delete
{	// default deleter for unique_ptr
constexpr default_delete() noexcept = default;

template<class _Ty2,
enable_if_t<is_convertible_v<_Ty2 *, _Ty *>, int> = 0>
default_delete(const default_delete<_Ty2>&) noexcept
{	// construct from another default_delete
}

void operator()(_Ty * _Ptr) const noexcept
{	// delete a pointer
    static_assert(0 < sizeof (_Ty),
    "can't delete an incomplete type");
    delete _Ptr;
}
};

可以看到主要接口为operator(),采用delete 释放内存。

_Unique_ptr_base

_Unique_ptr_base作为unique_ptr的基类,部分源码如下:

// CLASS TEMPLATE _Unique_ptr_base
template<class _Ty,
class _Dx>
class _Unique_ptr_base
{	// stores pointer and deleter
public:
typedef remove_reference_t<_Dx> _Dx_noref;
typedef typename _Get_deleter_pointer_type<_Ty, _Dx_noref>::type pointer;
//...
_Compressed_pair<_Dx, pointer> _Mypair;
};

可以看到,通过_Compressed_pair<_Dx, pointer> _Mypair;管理删除器和指针。而_Compressed_pair部分源码如下:


template<class _Ty1,
class _Ty2,
bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final
: private _Ty1
{	// store a pair of values, deriving from empty first
private:
_Ty2 _Myval2;

using _Mybase = _Ty1;	// for visualization
}

_Compressed_pair类通过继承自_Ty1(删除器),以达到当使用默认删除器时,通过EBO技术使得其不消耗额外的内存空间。详细来说就是:

如果不采用这种方式,那么必然在_Compressed_pair内部需要再添加一个变量持有删除器,那么_Compressed_pair的内存空间必然变成:

删除器内存空间(4)+指针空间(4)

而且即使我们使用默认的删除器也会如此,这样就比裸指针内存空间大。

而采用EBO的技术,则将_Compressed_pair继承自迭代器,由于默认删除器default_delete不包含非静态数据成员,因此空间为1,而通过EBO技术的优化,_Compressed_pair则会将这一个字节内存优化掉,因此只有:

指针空间(4)

的内存空间大小,与裸指针空间相同。

4.使用场景

首先,由于unique_ptr的独占性,因此比较适用于指针内容不会要求被共享的场景。

其次,由于添加了移动语义,且由于独占性导致移动后则有对方管理释放,因此在工厂函数中比较适合用unique_ptr返回创建的对象。

最后,对于传入删除器的场景,往往用于对象不需要/不允许释放,其他释放手段(如文件需要用fclose)等等场合。

三、shared_ptr

1.简介

  • shared_ptr是一种保存指针但共享指针所有权的一种智能指针,即多个shared_ptr可能保存同一个指针(注意是通过赋值、拷贝构造,而不是用指针初始化多个shared_ptr)。
    • 注意,如果一个指针多次使用shared_ptr构造保存,则会导致多次释放的问题。
  • shared_ptr管理的指针在以下两种情况下会被释放:
    • 管理指针的最后一个shared_ptr对象被释放
    • 管理指针的最后一个shared_ptr对象调用reset(p)或operator=()时。
  • shared_ptr也可以提供删除器,但是并不是作为类模板参数,而是构造函数的函数模板参数。
  • shared_ptr的共享实例的任何操作都是线程同步的,但对于保存的指针的操作无法保证这一点。

2.接口简介

shared_ptr以通过计数的方式共享资源。

成员函数名

功 能

operator*()

重载 * 运算符,获取当前保存指针指向的数据。

operator->()

重载 -> 运算符,当智能指针为自定义类型时,通过 -> 运算符可以获取其内部的指定成员。

operator =()

重载了 = 运算符,将计数成员和指针成员赋值给当前智能指针。

operator []()

重载了 [] 运算符,当 shared_ptr 中指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。

get()

获取当前 shared_ptr中 指针内部包含的原始指针。

use_count()

返回共享的智能指针数,也就是这个原始指针被多少个shared_ptr共享。

operator bool()

重载bool运算符,判断shared_ptr的指针是否为空。

reset([p])

重置存储的原始指针,如果不带参数,则表示当前shared_ptr置空,与之共享的shared_ptr的计数减1;

swap(x)

交换当前 shared_ptr 指针和同类型的 x 指针。

3.类设计

UML类图

shared_ptr

shared_ptr并没有任何数据成员(数据成员来自于基类_Ptr_base)。类声明如下:

template<class _Ty>
	class shared_ptr
		: public _Ptr_base<_Ty>

而其中大部分接口也都是间接调用基类_Ptr_base的接口,因此我们主要看一下_Ptr_base。

_Ptr_base

成员

基类拥有两个成员

element_type * _Ptr{nullptr};
_Ref_count_base * _Rep{nullptr};

前者_Ptr为保存的指针。而后者_Rep则是用于计数的指针(详细参考下面的_Ref_count_base)

拷贝
template<class _Ty2>
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
{	// implement shared_ptr's (converting) copy ctor
    if (_Other._Rep)
    {
        _Other._Rep->_Incref();
    }

    _Ptr = _Other._Ptr;
    _Rep = _Other._Rep;
}

shared_ptr的拷贝操作都调用的基类_Copy_construct_from函数,从上面的源码可以看到实现也比较简单:

  • 先调用被拷贝对象的Incref()函数,将计数+1;
  • 然后再将被拷贝对象保存的指针和计数器拷贝给当前对象。

_Ref_count_base

成员
_Atomic_counter_t _Uses;
_Atomic_counter_t _Weaks;
  • 计数器拥有两个数据成员分别用于shared_ptr和weak_ptr的计数(所以weak_ptr也是有计数滴)
  • 而这两个数据成员都是_Atomic_counter_t类型,以此数据操作的线程安全。而shared_ptr向上也只有这两个数据成员,因此shared_ptr的所有操作都是线程安全的。
构造
_Ref_count_base()
: _Uses(1), _Weaks(1)	// non-atomic initializations
{	// construct
}

构造时默认_Uses和_Weak都初始化为1

计数
void _Incref()
{	// increment use count
    _MT_INCR(_Uses);
}

void _Incwref()
{	// increment weak reference count
    _MT_INCR(_Weaks);
}

调用_MT_INCR对强计数和弱计数分别累加。_MT_INCR和下面的_MT_DECR都是平台相关的累加/减操作。

void _Decref()
{	// decrement use count
    if (_MT_DECR(_Uses) == 0)
    {	// destroy managed resource, decrement weak reference count
        _Destroy();
        _Decwref();
    }
}

void _Decwref()
{	// decrement weak reference count
    if (_MT_DECR(_Weaks) == 0)
    {
        _Delete_this();
    }
}
  • _Decref调用_MT_DECR对强计数-1,
  • 并判断是否计数为0,如果是,则调用_Destroy删除器(_Ref_count_base下的_Destroy为纯虚函数,具体实现在子类中,主要也就是用于释放管理的指针)。
  • 并调用_Decwref()。
  • _Decwref调用_MT_DECR对强计数-1,
  • 并判断是否计数为0,如果是,则调用_Delete_this(同_Destroy一样也为纯虚函数,子类中用于释放计数器本身)。
  • 因此当use_count减为0时,管理的指针对象会被释放,但删除器并不一定会被立即释放,而是等弱引用计数清空,才会释放。
_Ref_count
template<class _Ty>
class _Ref_count
: public _Ref_count_base
{	// handle reference counting for pointer without deleter
public:
explicit _Ref_count(_Ty * _Px)
: _Ref_count_base(), _Ptr(_Px)
{	// construct
}

private:
virtual void _Destroy() noexcept override
{	// destroy managed resource
    delete _Ptr;
}

virtual void _Delete_this() noexcept override
{	// destroy self
    delete this;
}

_Ty * _Ptr;
};

计数器_Ref_count_base的子类,将保存的指针传入,并重写_Destroy和_Delete_this,实现释放操作。

_Ref_count_resource

// CLASS TEMPLATE _Ref_count_resource
template<class _Resource,
class _Dx>
class _Ref_count_resource
: public _Ref_count_base
{	// handle reference counting for object with deleter
public:
_Ref_count_resource(_Resource _Px, _Dx _Dt)
: _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt), _Px)
{	// construct
}

virtual void * _Get_deleter(const type_info& _Typeid) const noexcept override
{	// return address of deleter object
    #if _HAS_STATIC_RTTI
    if (_Typeid == typeid(_Dx))
    {
        return (const_cast<_Dx *>(_STD addressof(_Mypair._Get_first())));
    }
    #else /* _HAS_STATIC_RTTI */
    (void)_Typeid;
    #endif /* _HAS_STATIC_RTTI */

    return (nullptr);
}

private:
virtual void _Destroy() noexcept override
{	// destroy managed resource
    _Mypair._Get_first()(_Mypair._Get_second());
}

virtual void _Delete_this() noexcept override
{	// destroy self
    delete this;
}

_Compressed_pair<_Dx, _Resource> _Mypair;
};

而对于资源类型,则实现了_Ref_count_resource传入删除器定制释放操作。其中_Ref_count_resource的数据成员又是_Compressed_pair。

_Ref_count_resource_alloc

// CLASS TEMPLATE _Ref_count_resource_alloc
template<class _Resource,
class _Dx,
class _Alloc>
class _Ref_count_resource_alloc
: public _Ref_count_base
{	// handle reference counting for object with deleter and allocator
public:
_Ref_count_resource_alloc(_Resource _Px, _Dx _Dt, const _Alloc& _Ax)
: _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _STD move(_Dt),
_One_then_variadic_args_t(), _Ax, _Px)
{	// construct
}

virtual void * _Get_deleter(const type_info& _Typeid) const noexcept override
{	// return address of deleter object
    #if _HAS_STATIC_RTTI
    if (_Typeid == typeid(_Dx))
    {
        return (const_cast<_Dx *>(_STD addressof(_Mypair._Get_first())));
    }
    #else /* _HAS_STATIC_RTTI */
    (void)_Typeid;
    #endif /* _HAS_STATIC_RTTI */

    return (nullptr);
}

private:
using _Myalty = _Rebind_alloc_t<_Alloc, _Ref_count_resource_alloc>;

virtual void _Destroy() noexcept override
{	// destroy managed resource
    _Mypair._Get_first()(_Mypair._Get_second()._Get_second());
}

virtual void _Delete_this() noexcept override
{	// destroy self
    _Myalty _Al = _Mypair._Get_second()._Get_first();
    allocator_traits<_Myalty>::destroy(_Al, this);
    _Deallocate_plain(_Al, this);
}

_Compressed_pair<_Dx, _Compressed_pair<_Myalty, _Resource>> _Mypair;
};

对于第三个子类_Ref_count_resource_alloc,则是传入了删除器和分配器,用于资源的释放和分配。此外其数据成员为两层_Compressed_pair,因为删除器和分配器都有可能为空类,以此节省空类时的空间。

四、weak_ptr

1.简介

  • weak_ptr以弱引用的方式持有指针,它并不拥有指针的所有权
  • weak_ptr需要通过lock接口获取临时的shared_ptr才能访问指针。
  • weak_ptr比较重要的一个作用是打破shared_ptr的环形引用问题。

2.接口简介

成员函数名

功 能

operator =()

重载了 = 运算符,将计数成员和指针成员赋值给当前智能指针。

reset()

没有参数。释放当前weak_ptr对象

use_count()

返回共享的智能指针数,也就是这个原始指针被多少个shared_ptr共享。

expired()

判断当前引用的对象(指针)是否被释放

lock()

返回一个临时的shared_ptr,共享保存的指针。如果指针被释放,则返回一个空的shared_ptr

3.类设计

weak_ptr

template<class _Ty>
class weak_ptr
: public _Ptr_base<_Ty>

weak_ptr和shared_ptr一样,继承自_Ptr_base,整体类结构与shared_ptr类似,只不过基于_Ptr_base封装了一些不同的构造和操作入口。

基类_Ptr_base中的计数器_Ref_count_base中的成员_Weaks用于weak_ptr的计数。

weak_ptr比较重要的两个函数是expired和lock:


_NODISCARD bool expired() const noexcept
{	// return true if resource no longer exists
    return (this->use_count() == 0);
}

其中expired则是调用了基类的use_count:

_NODISCARD long use_count() const noexcept
{	// return use count
    return (_Rep ? _Rep->_Use_count() : 0);
}

来所引用的资源是否被释放。

而lock则是通过基类_Construct_from_weak函数创建一个临时shared_ptr,并通过移动语义返回。

_NODISCARD shared_ptr<_Ty> lock() const noexcept
{	// convert to shared_ptr
    shared_ptr<_Ty> _Ret;
    (void) _Ret._Construct_from_weak(*this);
    return (_Ret);
}

基类的_Construct_from_weak主要是调用了计数器的_Incref_nz函数实现_Uses的增长,然后在进行拷贝操作。

template<class _Ty2>
bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other)
{	// implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()
    if (_Other._Rep && _Other._Rep->_Incref_nz())
    {
        _Ptr = _Other._Ptr;
        _Rep = _Other._Rep;
        return (true);
    }

    return (false);
}

这里之所以使用_Incref_nz()是为了确保跨线程时_Uses自增成功。

  • 17
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值