智能指针是在 C + + 14 C++14 C++14中新引入的,所以在编译的时候最好加入 " − s t d = c + + 14 " "-std=c++14" "−std=c++14"的编译选项。智能指针一共有两种,分别是 u n i q u e _ p t r unique\_ptr unique_ptr和 s h a r e d _ p t r shared\_ptr shared_ptr。
u n i q u e _ p t r unique\_ptr unique_ptr
u n i q u e _ p t r unique\_ptr unique_ptr可以使用 m a k e _ u n i q u e make\_unique make_unique来生成:
template<typename _Tp, typename... _Args>inline typename _MakeUniq<_Tp>::__single_objectmake_unique(_Args&&... __args){ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
可以看出 m a k e _ u n i q u e make\_unique make_unique是一个模板函数,将返回一个 _ T p \_Tp _Tp类型的指针,也就是假设有一个 p o i n t point point类:
struct point
{int x, y;point(int x, int y){this->x = x;this->y = y;}
};
然后声明一个指针:
std::unique_ptr<point> x = make_unique<point>(3, 5);
则 x x x为一个指向 p o i n t ( 3 , 5 ) point(3,5) point(3,5)的指针,然而由于其" u n q i u e unqiue unqiue"的特性, x x x不可被拷贝构造以及拷贝赋值,在源码里,其拷贝构造以及拷贝赋值被定义成以下的形式:
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
在 C + + C++ C++中,“ = d e l e t e = delete =delete"是一种特殊的函数声明方式,用于禁用或删除某个函数的默认实现。当一个函数被声明为” = d e l e t e = delete =delete"时,编译器将不会生成该函数的默认实现,并且在尝试调用该函数时会引发编译错误。
然而,有的时候需要将 x x x指向的内存转给其他指针,那么这个时候,只有唯一的一种方法,就是:
auto y = std::move(x);
//or std::unique_ptr<point> y = std::move(x);
s h a r e d _ p t r shared\_ptr shared_ptr
s h a r e d _ p t r shared\_ptr shared_ptr不同于 u n i q u e _ p t r unique\_ptr unique_ptr,其可以通过拷贝赋值给其他指针,以下分别是其拷贝构造以及拷贝赋值函数。
shared_ptr& operator=(const shared_ptr& _Right) noexcept{ // assign shared ownership of resource owned by _Rightshared_ptr(_Right).swap(*this);return (*this);}
shared_ptr(const shared_ptr& _Other) noexcept{ // construct shared_ptr object that owns same resource as _Otherthis->_Copy_construct_from(_Other);}
也就是说, s h a r e d _ p t r shared\_ptr shared_ptr可以通过以下方式构造:
std::shared_ptr<point> x = make_shared<point>(3, 5);
auto y = x;
auto z(x);
同时可以通过 u s e _ c o u n t use\_count use_count方法统计一块相同的内存被几个指针共享:
cout << x.use_count() << endl;
共享指针有以下几个 t r i c k trick trick
- 当共享指针被拷贝构造或者拷贝赋值的时候,指向的内存才算被共享了一次,所以上面的那段代码输出的结果为 3 3 3,然而如果是进行浅拷贝的话,不算做一次共享:
auto y = std::move(x);
cout<<y.use_count()<<x.use_count<<endl;
//该结果为3 0
- 如果是传入函数并且打印 u s e _ c o u n t use\_count use_count,也有以下两种情况。
void func(std::shared_ptr<point> x)
{cout << x.use_count() << endl;
}
int main(void)
{std::shared_ptr<point> x = make_shared<point>(3, 5);auto y = x;auto z(x);cout << x.use_count() << endl;func(std::move(x));//这个右值引用如果给一个左值里面就空了cout << x.use_count() << endl;
}
//本结果为
//3 3 0
//如果调用x的其他属性会报段错误。
void func(std::shared_ptr<point>&& x)
{cout << x.use_count() << endl;
}
int main(void)
{std::shared_ptr<point> x = make_shared<point>(3, 5);auto y = x;auto z(x);cout << x.use_count() << endl;func(std::move(x));//这个右值引用如果给一个左值里面就空了cout << x.use_count() << endl;
}
//这个结果为3 3 3
如果不按右值引用传入:
void func(std::shared_ptr<point> x)
{cout << x.use_count() << endl;
}
int main(void)
{std::shared_ptr<point> x = make_shared<point>(3, 5);auto y = x;auto z(x);cout << x.use_count() << endl;func(x);//这个右值引用如果给一个左值里面就空了cout << x.use_count() << endl;
}
//这个结果是3 4 3