———-引入智能指针的目的,个人;理解有如下两点:
1.自动释放内存:智能指针类能记录多少个shared_ptr指向相同的对象,并在引用计数值为0时自动释放对象所占用的内存。
2.内存共享:让多个对象共享底层数据。
C++动态内存(malloc & free, new & delete)
程序使用动态内存出于以下三种原因之一:
- 程序不知道自己需要使用多少对象
- 程序不知道所需对象的准确类型
- 程序需要在多个对象间共享数据
vector<string> v1;
{//新作用域
string str[] = {"a", "an", "the"};
int size = sizeof(str) / sizeof(str[0]);
vector<string> v2(str, str + size);
v1 = v2;
}//v2被销毁,v1中包含三个元素
当拷贝一份vector时,原vector和副本vector中元素是相互分离的。
一般而言,如果两个对象共享底层的数据,当某个对象被销毁时,我们不能当方面的销毁底层数据。
Blob<string> b1;
{//新作用域
Blob<string> b2 = {"a", "an", "the"};
b1 = b2;//b1和b2共享相同的元素
}
对象b1与b2具有引用相同的底层元素。
实现Blob类如下:
class strBlob
{
public:
typedef std::vector<string>::size_type size_type;
strBlob();
strBlob(initializer_list<string> i1);
size_type size() const { return data->size(); };
bool empty() const{ return data->empty(); };
//添加和删除元素
void push_back(const string &t) {data->push_back(t); };
void pop_back();
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string &msg) const;
}
shared_ptr与new的结合使用
默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。
shared_ptr<string> clone(int p)
{
//必须显示地调用int *创建shared_ptr<int>
return shared_ptr<int>(new int(p));
}
不要混合使用普通指针和智能指针
void process(shared_ptr<int> ptr)
{
//使用ptr
}//ptr离开作用域,被销毁
process采用传值方式传递形参,因此实参会被拷贝给一个临时变量ptr,拷贝实参会递增引用计数。
shared_ptr<int> p(new int(42));//引用计数为1;
process(p); //引用计数为2,执行完process后引用计数变为1
int i = *p;//p的引用计数为1;
智能指针删除器
struct destination;
struct connection;
connection connect(destination *d);
void disconnection(connection);
void f(destination *dd)
{
connection conn = connect(dd);
//使用完conn后并未及时关闭,需要单独调用disconnection
}
以上代码中若connection存在析构函数,还可以在析构函数中调用disconnect。但是不存在析构函数,就可以使用shared_ptr,与采用shared_ptr自动会调用delete避免内存泄漏的原理是一样的。
修改如下:
void end_connection(destionation *d){ disconnect(p); };
void f(destination *dd)
{
connection conn = connect(dd);
shared_ptr<connection> p(&conn, end_connection);
}
unique_ptr
某一时刻只能有一个unique_ptr指向一个给定对象,unique_ptr与对象是一一对应的关系。
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1); //错误:unique_ptr不支持拷贝,unique_ptr没有对应的拷贝构造函数
unique_ptr<string> p3;
p3 = p2; //错误:unique_ptr不支持拷贝,unique_ptr没有对应的拷贝构造函数
unique_ptr操作
- unique_ptr〈T〉 u1:空unique_ptr,可以指向类型为T的对象;u1会使用delete来释放它的指针。
- unique_ptr〈T, D〉 u2:u2会使用一个类型为D的可调用对象来释放它的指针。
- unique_ptr〈T, D〉 u(d)
- u = nullptr
- u.release() :u放弃对指针的控制权,返回指针,并将u置为空
- u.reset():释放u指向的对象
- u.reset(q):如果提供了内置q,令u指向这个对象;否则将u置位空。
指向release之后,unique_ptr会切断与之前指向对象的联系,并返回当初指向的对象,这时就需要使用返回的对象初始化另一个智能指针。
p2.release();//错误:p2不会释放内存,而且我们丢失了指针
auto p = p2.release(); //正确,用完后必须delete(p)
weak_ptr操作
weak_ptr是一种不控制所指向对象生命周期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到shared_ptr上不会改变shared_ptr的引用计数。
- weak_ptr〈T〉w:指向类型为T的空weak_ptr
- weak_ptr〈T〉w(sp):与shared_ptr sp指向相同对象的weak_ptr,但是T必须能转换为sp可以指向的类型
- w.reset()
- w.use_count();
- w.expired();
- w = p