c++ 智能指针
c++ 智能指针
c++ 有三种智能指针:
- shared_ptr
- weak_ptr
- unique_ptr
头文件 <memory>
关于 auto_ptr 指针
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));
// move 后 p1 p2 都指向空指针
if (p1.get() == nullptr)
cout << "p1 is nullptr" << endl;
if (p2.get() == nullptr)
cout << "p2 is nullptr" << endl;
cout << "vec[0]: " << *vec[0] << endl; // 输出:I'm p1
cout << "vec[1]: " << *vec[1] << endl; // 输出:I'm p2
// 风险来了:
// vec[1] 赋值给 vec[0] 后,首先 vec[1] 会先将自己原先托管的指针释放掉,然后接收托管 vec[2] 所托管的指针,
// 然后 vec[2] 所托管的指针指向NULL,也就是 vec[1]托管了 vec[2] 托管的指针,而 vec[2] 放弃了托管。
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, 不能这样定义
unique_ptr
C++11用更严谨的 unique_ptr 取代了auto_ptr。
unique_ptr 用法:
uniquer_ptr 是独占指针,只能有一个 unique_ptr 指针指向某个对象
通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象。
unique_ptr 可以不占有对象,此时 unique_ptr 为空
unique_ptr 有两个版本:
- 管理单个对象(例如以 new 分配)
- 管理动态分配的对象数组(例如以 new[] 分配)
类可以移动构造 (MoveConstructible) 和 移动赋值 (MoveAssignable);不能复制构造 (CopyConstructible) 和 复制赋值 (CopyAssignable) 。(只能有一个 unique_ptr 指针指向某个对象)
构造方式
#include <iostream>
#include <memory>
using namespace std;
struct A { // object to manage
A() { cout << "A ctor" << endl; }
A(const A&) { cout << "A copy ctor" << endl; }
A(A&&) { cout << "A move ctor" << endl; }
~A() { cout << "~A dtor" << endl; cout << 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()(A* p) const {
cout << "D is deleting a A" << endl;
delete p;
}
};
int main()
{
unique_ptr<A> up1; // up1 is empty
unique_ptr<A> up1b(nullptr); // up1b is empty
{
printf("*******up2******\n");
unique_ptr<A> up2(new A); //up2 now owns a A
} // A deleted
D d;
{
printf("*******up3, up3b******\n");
// deleter type is not a reference
unique_ptr<A, D> up3(new A, d); // deleter copied
// deleter type is a reference
unique_ptr<A, D&> up3b(new A, d); // up3b holds a reference to d
}
{
printf("*******up4******\n");
// deleter is not a reference
unique_ptr<A, D> up4(new A, D()); // deleter moved
}
{
printf("*******up5******\n");
unique_ptr<A> up5a(new A);
unique_ptr<A> up5b(move(up5a)); // ownership transfer
}
{
printf("*******up6******\n");
unique_ptr<A, D> up6a(new A, d); // D is copied
unique_ptr<A, D> up6b(move(up6a)); // D is moved
unique_ptr<A, D&> up6c(new A, d); // D is a reference
unique_ptr<A, D> up6d(move(up6c)); // D is copied
}
{
printf("*******up array******\n");
unique_ptr<A[]> up(new A[3]);
} // three A objects deleted
}
注意:
只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const unique_ptr 所管理,则它被限定在创建指针的作用域中。
shared_ptr
共享指针,是为多个所有者可能必须管理对象在内存中的生命周期的方案设计。 在初始化一个 shared_ptr 之后,可复制它,按值将其传入函数参数,然后将其分配给其他 shared_ptr 实例。 所有实例均指向同一个对象,并共享对一个“控制块”(每当新的 shared_ptr 添加、超出范围或重置时增加和减少引用计数)的访问权限。 当引用计数达到零时,控制块将删除内存资源和自身。
简单实现 shared_ptr
#include <iostream>
#include <mutex>
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(const myShared_ptr& sp)
: _ptrCount(sp._ptrCount), _ptr(sp._ptr), _mutex(sp._mutex) {
addCount();
}
~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*() const { return *_ptr; }
T* operator->() const { return _ptr; }
int useCount() const { return *_ptrCount; }
T* get() const { return _ptr; }
private:
void release() {
_mutex->lock();
bool flagMutex = false;
if (--(*_ptrCount) == 0) {
delete _ptrCount;
if (_ptr)
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
weak_ptr
为了解决 shared_ptr 循环引用的问题而引入。
Weak_ptr允许共享,但不拥有一个对象。 它的对象是由shared_ptr创建的
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()
{
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;
}
//输出 此时 A 和 B 正常析构。
constuctor A
constuctor B
1
1
deconstuctor B
deconstuctor A
改成如下代码:
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
aPtr->_b = bPtr; // 令_b 指向 bPtr
bPtr->_a = aPtr; // 令_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