C++11提供了三个智能指针,std::shared_ptr,std::unique_ptr,std::weak_ptr。最常用的是shared_ptr和unique_ptr。
(1)std::shared_ptr
shared_ptr是共享指针,通过在控制块中增加引用计数的方式实现多个指针指向同一个对象。每当拷贝构造或者拷贝赋值时,对象的引用计数都会+1,每当指针对象析构时,引用计数-1,直到引用计数为0,释放实际指针对象。
std::shared_ptr<T> sp(new T()) 形式声明效率上没有 std::shared_ptr<T> sp = std::make_shared<T>()高,因为前一种声明方式在实现上需要new两次(一次是new T, 一次是 new 控制结构),而后者在实现上一般都是一次。
示例如下:
#include <iostream>
#include <memory>int main() {
{ std::shared_ptr<int> sp1;{
std::shared_ptr<int> sp2(new int(10)); sp1 = sp2; std::cout << "sp1.count=" << sp1.use_count() << std::endl; // use_count为2 } std::cout << "sp1.count=" << sp1.use_count() << std::endl; // use_count为1 }return 0;
}
2,std::unique_ptr
unique_ptr顾名思义,只允许一个指针指向同一个对象。unique_ptr通过禁止拷贝构造函数和拷贝赋值运算符到达无法让多个指针指向同一个对象的目的。unique_ptr通过移动构造函数和移动赋值运算符达到指针对象资源转移的目的(保证某一时刻只有一个指针指向该对象)。
同样,std::unique_ptr<T> sp(new T()) 形式声明效率上没有 std::unique_ptr<T> sp = std::make_unique<T>()高,因为前一种声明方式在实现上需要new两次(一次是new T, 一次是 new 控制结构),而后者在实现上一般都是一次。
示例如下:
#include <iostream>
#include <memory>int main() {
std::unique_ptr<int> sp1(new int(10)); // std::unique_ptr<int> sp2 = sp1; // 编译错误,拷贝构造函数 deleted std::unique_ptr<int> sp2 = std::move(sp1); // ok,使用移动构造函数,实现资源转移return 0;
}3,std::weak_ptr
std::shared_ptr在循环引用的情况下会有内存泄漏的问题,示例如下:
#include <iostream>
#include <memory>class Child;
class Parent;class Parent {
private: std::shared_ptr<Child> ChildPtr;public:
void setChild(std::shared_ptr<Child> child) { this->ChildPtr = child; }~Parent() {}
};class Child {
private: std::shared_ptr<Parent> ParentPtr;public:
void setPartent(std::shared_ptr<Parent> parent) { this->ParentPtr = parent; }~Child() {}
};int main() {
std::weak_ptr<Parent> wpp; std::weak_ptr<Child> wpc; { std::shared_ptr<Parent> p(new Parent); std::shared_ptr<Child> c(new Child); p->setChild(c); c->setPartent(p); wpp = p; wpc = c; std::cout << p.use_count() << std::endl; // 2 std::cout << c.use_count() << std::endl; // 2 } std::cout << wpp.use_count() << std::endl; // 1 std::cout << wpc.use_count() << std::endl; // 1 return 0; } 说明:本质上来说,由于循环相互引用,导致双方都没有减少对方的引用计数,导致双方资源都没有释放掉。std::weak_ptr提供了一种资源监视的方法:使用weak_ptr指向一个shared_ptr,并不会增加对象的引用计数,但是可以访问shared_ptr的控制块结构。解决上述循环引用问题的示例代码如下:
#include <iostream>
#include <memory>class Child;
class Parent;class Parent {
private: std::shared_ptr<Child> ChildPtr;public:
void setChild(std::shared_ptr<Child> child) { this->ChildPtr = child; }~Parent() {}
};class Child {
private: // std::shared_ptr<Parent> ParentPtr; std::weak_ptr<Parent> ParentPtr;public:
void setPartent(std::shared_ptr<Parent> parent) { this->ParentPtr = parent; }~Child() {}
};int main() {
std::weak_ptr<Parent> wpp; std::weak_ptr<Child> wpc; { std::shared_ptr<Parent> p(new Parent); std::shared_ptr<Child> c(new Child); p->setChild(c); c->setPartent(p); wpp = p; wpc = c; std::cout << p.use_count() << std::endl; // 1 std::cout << c.use_count() << std::endl; // 2 } std::cout << wpp.use_count() << std::endl; // 0 std::cout << wpc.use_count() << std::endl; // 0 return 0; }