shared_ptr
shared_ptr
会进行引用计数,引用计数为0时自动销毁
类似下面的实现
template<class T>
class shared_ptr {
private:
T *p;
size_t *use;
public:
shared_ptr(T *s = nullptr): p(s) {
use = new size_t();
if (s) *use = 1;
}
shared_ptr(const shared_ptr<T>& lhs): p(lhs.p), use(lhs.use) {
++*use;
}
shared_ptr& operator=(const shared_ptr<T>& lhs) {
if (this != &lhs) {
++*lhs.use;
if (--*use < 1) {
delete p;
delete use;
}
p = lhs.p;
use = lhs.use;
}
return *this;
}
size_t use_count() { return *use; }
~shared_ptr() {
if (--*use < 1) {
delete p;
delete use;
}
}
};
具体应用
void ex3() {
puts(">>>>>Entering ex3<<<<<");
auto e1 = make_shared<Entity>();
cout << e1.use_count() << endl;
{
puts("-----Entering scope-----");
auto e2 = e1;
cout << e1.use_count() << endl;
auto e3 = move(e2); // move是ownership转移
cout << e1.use_count() << endl;
puts("-----Leaving scope-----");
}
cout << e1.use_count() << endl;
puts(">>>>>Leaving ex3<<<<<");
}
int main() {
ex3();
return 0;
}
>>>>>Entering ex3<<<<<
Entity created!
1
-----Entering scope-----
2
2
-----Leaving scope-----
1
>>>>>Leaving ex3<<<<<
Entity destroyed!
shared_ptr循环引用问题
class B;
class A {
public:
A() { cout << "A constructor" << endl; }
shared_ptr<B> b;
void test() { cout << "A test" << endl; }
~A() { cout << "A destructor" << endl; }
};
class B {
public:
B() { cout << "B constructor" << endl; }
shared_ptr<A> a;
void test() { cout << "B test" << endl; }
~B() { cout << "B destructor" << endl; }
};
int main() {
shared_ptr<A> pa = make_shared<A>();
shared_ptr<B> pb = make_shared<B>();
pa->b = pb;
pb->a = pa;
cout << pa->b.use_count() << endl;
cout << pb->a.use_count() << endl;
return 0;
}
A constructor
B constructor
2
2 // 没有调用析构函数
这里pa
指针指向的A
对象中的指针指向B
对象,pb
指针指向的B
对象中的指针指向A
对象,所以A
对象和B
对象的引用计数都为2
程序结束时,pb
指针先析构,这样B
对象的引用计数减一变成1,还不能释放,pa
指针再析构,这样A
对象的引用计数减一变成1,也不能释放,所以就变成两个对象相互引用,都不能释放,导致内存泄漏
解决方法:声明对象时使用强指针
shared_ptr
,引用对象时使用弱指针weak_ptr
这里类A
需要引用B
对象,所以可以用weak_ptr
替换shared_ptr
,类B
同理
class B;
class A {
public:
A() { cout << "A constructor" << endl; }
weak_ptr<B> b; // 换成weak_ptr
void test() { cout << "A test" << endl; }
~A() { cout << "A destructor" << endl; }
};
class B {
public:
B() { cout << "B constructor" << endl; }
weak_ptr<A> a; // 换成weak_ptr
void test() { cout << "B test" << endl; }
~B() { cout << "B destructor" << endl; }
};
int main() {
shared_ptr<A> pa = make_shared<A>();
shared_ptr<B> pb = make_shared<B>();
pa->b = pb;
pb->a = pa;
cout << pa->b.use_count() << endl;
cout << pb->a.use_count() << endl;
return 0;
}
A constructor
B constructor
1
1
B destructor // 调用B的析构函数
A destructor // 调用A的析构函数
改成weak_ptr
后,不会增加对象的引用计数,所以A
对象只有指针pa
引用,所以引用计数为1,B
对象只有指针pb
引用,所以引用计数也为1
指针pb
析构时,B
对象引用计数减一后变成0,调用析构函数,释放内存,指针pa
析构时,A
对象的引用计数减一后变成0,也调用析构函数,释放内存,这样就不会内存泄漏了
weak_ptr
- 不具有普通指针的行为,没有重载
operator*
和operator->
- 没有共享资源,它的构造不会引起引用计数增加
- 用于协助
shared_ptr
来解决循环引用问题 - 可以从一个
shared_ptr
或者另外一个weak_ptr
对象构造,进而可以间接获取资源的弱共享权
weak_ptr
使用前检查对象是否还存在,确认存在才能使用
void observe(weak_ptr<Entity> ew) {
puts("*****Entering observe*****");
if (shared_ptr<Entity> spt = ew.lock()) { // 如果对象可用,会用一个shared_ptr指向它
cout << spt.use_count() << endl; // 2
cout << "entity still alive" << endl;
} else {
cout << "entity was expired" << endl;
}
puts("*****Leaving observe*****");
}
void ex4() {
puts(">>>>>Entering ex4<<<<<");
weak_ptr<Entity> ew;
{
puts("-----Entering scope-----");
auto e1 = make_shared<Entity>();
cout << e1.use_count() << endl; // 1
ew = e1;
cout << e1.use_count() << endl; // 1,引用计数没有增加
observe(ew);
puts("-----Leaving scope-----");
} // 离开之后共享指针对象就销毁了
observe(ew);
puts(">>>>>Leaving ex4<<<<<");
}
int main(int argc, char const *argv[]) {
ex4();
return 0;
}
>>>>>Entering ex4<<<<<
-----Entering scope-----
Entity created!
1
1
*****Entering observe*****
2
entity still alive
*****Leaving observe*****
-----Leaving scope-----
Entity destroyed!
*****Entering observe*****
entity was expired
*****Leaving observe*****
>>>>>Leaving ex4<<<<<
unique_ptr
采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个pointer
拥有
类似下面的实现
template<class T>
class unique_ptr {
private:
T* p;
public:
unique_ptr() :p() {}
unique_ptr(T* s) :p(s) {}
~unique_ptr() { delete p; }
unique_ptr(const unique_ptr&) = delete; // 不能拷贝构造
unique_ptr& operator=(const unique_ptr&) = delete; // 不能赋值构造
unique_ptr(unique_ptr&& s) :p(s.p) { s.p = nullptr }
unique_ptr& operator=(unique_ptr s) {
delete p;
p = s.p;
s.p = nullptr;
return *this;
}
T* operator->() const { return p; }
T& operator*() const { return *p; }
};
- 无法进行拷贝与赋值操作
unique_ptr<int> ptr(new int(1));
unique_ptr<int> ptr1(ptr); // error
unique_ptr<int> ptr2 = ptr; // error
- 显示的所有权转移(通过move语义)
unique_ptr<int> ptr(new int(1));
unique_ptr<int> ptr1 = move(ptr); // ok
- 作为容器元素存储在容器中
unique_ptr<int> ptr(new int(1));
vector<unique_ptr<int>> v;
v.push_back(ptr); // error, 不能拷贝
v.push_back(move(ptr)); // ok, 可以移动
cout << *ptr << endl; // error, 移动之后就不能再用了
#include <iostream>
#include <memory>
using namespace std;
class Entity {
public:
Entity() { cout << "Entity created!" << endl; }
~Entity() {cout << "Entity destroyed!" << endl; }
};
void ex1() {
puts(">>>>>Entering ex1<<<<<");
{
puts("-----Entering scope-----");
auto e1 = make_unique<Entity>();
puts("-----Leaving scope-----");
}
puts(">>>>>Leaving ex1<<<<<");
}
int main() {
ex1();
return 0;
}
>>>>>Entering ex1<<<<<
-----Entering scope-----
Entity created!
-----Leaving scope-----
Entity destroyed! // 离开scope作用域就被销毁了
>>>>>Leaving ex1<<<<<
Ownership
转移到foo
里面,所以离开foo
之后就销毁了move
是ownership
的直接转移,调用者不再拥有对象
void foo(unique_ptr<Entity>) {
puts("-----Entering foo-----");
puts("-----Leaving foo-----");
}
void ex2() {
puts(">>>>>Entering ex2<<<<<");
auto e1 = make_unique<Entity>();
foo(move(e1)); // 移动拷贝
puts(">>>>>Leaving ex2<<<<<");
}
int main() {
ex2();
return 0;
}
>>>>>Entering ex2<<<<<
Entity created!
-----Entering foo-----
-----Leaving foo-----
Entity destroyed! // 对象转移到foo中,离开foo就被销毁了
>>>>>Leaving ex2<<<<<
unique_ptr
禁止对指针进行复制和赋值
class Fish {
public:
Fish() {cout << "constructor" << endl;}
~Fish() {cout << "destructor" << endl;}
void Swim() {
cout << "Fish swim in water" << endl;
}
};
void MakeFishSwim(const unique_ptr<Fish>& ptr) {
ptr->Swim();
}
int main() {
unique_ptr<Fish> pFish(new Fish);
pFish->Swim();
MakeFishSwim(pFish);
return 0;
}
// constructor
// Fish swim in water
// Fish swim in water
// destructor
auto_ptr
已被C++11弃用
auto_ptr
和unique_ptr
都是独占所有权的智能指针
类似于下面的实现
template<class T>
class auto_ptr {
T* p;
public:
auto_ptr(T* s) :p(s) {}
~auto_ptr() { delete p; }
auto_ptr(auto_ptr& a) {
p = a.p;
a.p = NULL; // 源指针被置空
}
auto_ptr& operator=(auto_ptr& a) {
delete p;
p = a.p;
a.p = NULL; // 源指针被置空
return *this;
}
T& operator*() const { return *p; }
T* operator->() const { return p; }
};
在使用auto_ptr
进行拷贝构造和拷贝赋值的时候,会造成所有权的转移,导致源指针被置空,这样源指针就无法使用了,但这并不符合拷贝的语义,拷贝的时候不应该修改原来的对象
auto_ptr<classA> a(new classA);
auto_ptr<classA> b = a;
a->Method();
这里b=a
的时候,指针a
就被置空了,后面再调用对应方法就会出错了
另外也有很多限制
- 不能在STL容器中使用,因为复制将导致数据无效
- 一些STL算法也可能导致
auto_ptr
失效,比如sort
算法 - 不能作为函数参数,因为这会导致复制,并且在调用后,导致原数据无效
- 如果作为类的成员变量,需要注意在类拷贝时候导致的数据无效