c++ 有三种智能指针:
头文件
C++98 提供了 auto_ptr 模板的解决方案, 在 c++11 被弃用,c++17中彻底移除,用 unique_ptr 代替
auto_ptr 被弃用的主要原因:
1.复制或者赋值都会改变资源的所有权,在STL容器中有重大风险
auto_ptr<string> p1(new string("I'm P1!"));
auto_ptr<string> p2(new string("I'm P2."));
vector<auto_ptr<string>> vec;
// 必须使用move修饰成右值,才可以进行插入容器中
vec.push_back(move(p1));
vec.push_back(move(p2));
cout << "vec[0]:" << *vec.[0] << endl; // 输出:I'm p1
cout << "vec[1]:" << *vec[1] << endl; // 输出:I'm p2
// p2赋值给p1后,首先p1会先将自己原先托管的指针释放掉,然后接收托管p2所托管的指针,
// 然后p2所托管的指针指向NULL,也就是p1托管了p2托管的指针,而p2放弃了托管。
p1 = p2;
// 风险来了:
vec[0] = vec[1];
cout << "vec[0]:" << *vec[0] << endl; // 输出: I'm p2
cout << "vec[1]:" << *vec[1] << endl; // ERROR, vec[1] 此时指向 nullptr
2.不支持对象数组的内存管理
auto_ptr<int[]> array(new int[5]); // ERROR, 不能这样定义
C++11用更严谨的 unique_ptr 取代了auto_ptr。
unique_ptr 用法:
uniquer_ptr 是独占指针,只能有一个 unique_ptr 指针指向某个对象
通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象。
unique_ptr 可以不占有对象,此时 unique_ptr 为空
unique_ptr 有两个版本:
类可以移动构造 (MoveConstructible) 和 移动赋值 (MoveAssignable);不能复制构造 (CopyConstructible) 和 复制赋值 (CopyAssignable) 。(只能有一个 unique_ptr 指针指向某个对象)
#include
#include
using namespace std;
struct Foo { // object to manage
Foo() { cout << "Foo ctor" << endl; }
Foo(const Foo&) { cout << "Foo copy ctor" << endl; }
Foo(Foo&&) { cout << "Foo move ctor" << endl; }
~Foo() { cout << "~Foo dtor" << endl; }
};
struct D { // deleter
D() {};
D(const D&) { cout << "D copy ctor" << endl; }
D(D&) { cout << "D non-const copy ctor" << endl;}
D(D&&) { cout << "D move ctor " << endl; }
void operator()(Foo* p) const {
cout << "D is deleting a Foo" << endl;
delete p;
};
};
int main()
{
cout << "Example constructor(1)..." << endl;
unique_ptr<Foo> up1; // up1 is empty
unique_ptr<Foo> up1b(nullptr); // up1b is empty
cout << "Example constructor(2)..." << endl;
{
unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
} // Foo deleted
cout << "Example constructor(3)..." << endl;
D d;
{ // deleter type is not a reference
unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
}
{ // deleter type is a reference
unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
}
cout << "Example constructor(4)..." << endl;
{ // deleter is not a reference
unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
}
cout << "Example constructor(5)..." << endl;
{
unique_ptr<Foo> up5a(new Foo);
unique_ptr<Foo> up5b(move(up5a)); // ownership transfer
}
cout << "Example constructor(6)..." << endl;
{
unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
unique_ptr<Foo, D> up6b(move(up6a)); // D is moved
unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
unique_ptr<Foo, D> up6d(move(up6c)); // D is copied
}
cout << "Example array constructor..." << endl;
{
unique_ptr<Foo[]> up(new Foo[3]);
} // three Foo objects deleted
}
注意:
只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const unique_ptr 所管理,则它被限定在创建指针的作用域中。
共享指针,是为多个所有者可能必须管理对象在内存中的生命周期的方案设计。 在初始化一个 shared_ptr 之后,可复制它,按值将其传入函数参数,然后将其分配给其他 shared_ptr 实例。 所有实例均指向同一个对象,并共享对一个“控制块”(每当新的 shared_ptr 添加、超出范围或重置时增加和减少引用计数)的访问权限。 当引用计数达到零时,控制块将删除内存资源和自身。
简单实现 shared_ptr
#include
#include
using namespace std;
template <typename T>
class myShared_ptr{
public:
myShared_ptr(T* ptr = nullptr)
: _ptrCount(new int(1)),
_ptr(ptr),
_mutex(new mutex()) {}
myShared_ptr(myShared_ptr& sp)
: _ptrCount(sp._ptrCount),
_ptr(sp._ptr),
_mutex(sp._mutex) {}
~myShared_ptr() {
release();
}
myShared_ptr<T> & operator=(const myShared_ptr<T>& sp) {
if (_ptr != sp._ptr) {
release();
_ptr = sp._ptr;
_ptrCount = sp._ptrCount;
_mutex = sp._mutex;
addCount();
}
return *this;
}
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
int useCount() { return *_ptrCount; }
T* get() { return _ptr; }
private:
void release() {
_mutex->lock();
bool flagMutex = false;
if (--(*_ptrCount) == 0) {
delete _ptrCount;
delete _ptr;
flagMutex = true;
}
_mutex->unlock();
if (flagMutex)
delete _mutex;
}
void addCount() {
_mutex->lock();
++(*_ptrCount);
_mutex->unlock();
}
private:
int* _ptrCount;
T* _ptr;
mutex* _mutex;
};
class B;
class A {
public:
A() { cout << "constuctor A" << endl; }
~A() { cout << "deconstuctor A" << endl; }
};
class B {
public:
B() { cout << "constuctor B" << endl; }
~B() { cout << "deconstuctor B" << endl; }
};
int main()
{
A *a = new A();
B *b = new B();
myShared_ptr<A> aPtr(a);
myShared_ptr<B> bPtr(b);
cout << aPtr.useCount() << endl;
cout << bPtr.useCount() << endl;
return 0;
}
// 输出
constuctor A
constuctor B
1
1
deconstuctor B
deconstuctor A
为了解决 shared_ptr 循环引用的问题而引入。
Weak_ptr允许共享,但不拥有一个对象。 它的对象是由shared_ptr创建的
class B;
class A {
public:
shared_ptr<B> _b;
A() { cout << "constuctor A" << endl; }
~A() { cout << "deconstuctor A" << endl; }
};
class B {
public:
shared_ptr<A> _a;
B() { cout << "constuctor B" << endl; }
~B() { cout << "deconstuctor B" << endl; }
};
int main()
{
shared_ptr<A> aPtr = make_shared<A>();
shared_ptr<B> bPtr = make_shared<B>();
cout << aPtr.use_count() << endl; // 输出 1
cout << bPtr.use_count() << endl; // 输出 1
return 0;
}
//输出
constuctor A
constuctor B
1
1
deconstuctor B
deconstuctor A
此时 A 和 B 正常析构。
int main()
{
shared_ptr<A> aPtr = make_shared<A>();
shared_ptr<B> bPtr = make_shared<B>();
cout << aPtr.use_count() << endl; // 输出 1
cout << bPtr.use_count() << endl; // 输出 1
aPtr->_b = bPtr;
bPtr->_a = aPtr;
cout << aPtr.use_count() << endl; // 输出 2
cout << bPtr.use_count() << endl; // 输出 2
return 0;
}
// 输出
constuctor A
constuctor B
1
1
2
2
没有调用 A 和 B 的析构函数。aPtr 和 bPtr 的引用计数都为 2。
此时就会造成内存泄漏,所以需要 weak_ptr 指针
class B;
class A {
public:
weak_ptr<B> _b; // 这里把 shared_ptr 换成 weak_ptr
A() { cout << "constuctor A" << endl; }
~A() { cout << "deconstuctor A" << endl; }
};
class B {
public:
weak_ptr<A> _a; // 这里把 shared_ptr 换成 weak_ptr
B() { cout << "constuctor B" << endl; }
~B() { cout << "deconstuctor B" << endl; }
};
int main()
{
shared_ptr<A> aPtr = make_shared<A>();
shared_ptr<B> bPtr = make_shared<B>();
cout << aPtr.use_count() << endl; // 输出 1
cout << bPtr.use_count() << endl; // 输出 1
aPtr->_b = bPtr;
bPtr->_a = aPtr;
cout << aPtr.use_count() << endl;
cout << bPtr.use_count() << endl;
return 0;
}
// 输出
constuctor A
constuctor B
1
1
1
1
deconstuctor B
deconstuctor A