new和delete创建和释放动态内存
new:分配一块随意初始化的内存给一个对象,并且返回指向该对象的指针(即返回值是动态内存的地址)delete:删除指针指向的对象,释放分配的内存
动态内存经常出现的问题:忘记释放内存空间;释放了内存空间但是指针依然指向该内存,出现野指针问题
为了让动态内存使用更简单,新的库添加了智能指针去管理动态对象
智能指针使用上跟普通指针一样,但是多了一点:会自动删除指针所指对象
智能指针有两种指针类型:shared_ptr和unique_ptr
shared_ptr:允许多个指针指向同一个对象
unique_ptr:拥有指针所指对象
跟vector一样,智能指针是有模版的,所以在我们创建智能指针的时候必须添加额外的信息
shared_ptr<string> p1; // shared_ptr that can point at a string
shared_ptr<list<int>> p2; // shared_ptr that can point at a list of ints
判断条件下使用智能指针,会判断指针是否为空
// if p1 is not null, check whether it's the empty string
if (p1 && p1->empty())
*p1 = "hi"; // if so, dereference p1 to assign a new value to that string
make_shared函数
最安全的使用和管理动态内存是调用库函数make_shared,这个函数分配和初始化动态对象并且返回一个指向该对象的shared_ptr指针
// p3 指向Int型,值为42
shared_ptr<int> p3 = make_shared<int>(42);
// p4 指向string,内容为“ 9999999999”
shared_ptr<string> p4 = make_shared<string>(10, '9');
// p5 指向Int型,默认初始化为0
shared_ptr<int> p5 = make_shared<int>();
我们也可以使用auto让指针更简单的获得返回结果
// p6 points to a dynamically allocated, empty vector<string>
auto p6 = make_shared<vector<string>>();
对于shared_ptr的进一步理解
auto p = make_shared<int>(42); // object to which p points has one user
auto q(p); // p and q point to the same object
// object to which p and q point has two users
shared_ptr有一个
关联计数器,当有新的shared_ptr指向对象时,计数器加一;当对象失去一个shared_ptr时,计数器减一。计数器为零时,shared_ptr就自动销毁指向的对象和释放该动态内存
//具体两个列子:
// factory returns a shared_ptr pointing to a dynamically allocated object
shared_ptr<Foo> factory(T arg)
{
return make_shared<Foo>(arg);
}
void use_factory(T arg)
{
shared_ptr<Foo> p = factory(arg);
// use p
} // p goes out of scope; the memory to which p points is automatically freed
/*这里只有一个shared_ptr指向创建的对象,当use_factory执行结束时,P同时也被销毁这时计数器减一变为零,shared_ptr就会自动的执行销毁和释放动作*/
shared_ptr<Foo> use_factory(T arg)
{
shared_ptr<Foo> p = factory(arg);
// use p
return p; // reference count is incremented when we return p
} // p goes out of scope; the memory to which p points is not freed
/*这里use_factory函数返回了P,意思是在调用这个函数的地方会有一个shared_ptr来接收,即新建了一个指向对象的shared_ptr,计数器加一,然后函数调用结束,P被销毁计数器减一,而此时还存在一个指向对象的shared_ptr,计数器不为零,所以不会销毁对象*/
注意:关联计数器是基于智能指针的,并不是基于内存。意思是有可能有多个不同的智能指针派系指向同一块内存,这样是很危险的,因为当一个智能指针派系删除到关联计数器为零时会释放内存空间,其他智能指针派系在对该内存空间进行操作就是非法操作!
shared_ptr<int> p(new int(42)); // 创建智能指针p,关联计数器基于p且为一
int *q = p.get(); //shared_ptr指针内置get函数可以返回同类型的普通指针
{
shared_ptr<int>(q); /*新建的shared_ptr指针,地址为q,即和p指向同一个内存空间。关联计数器基于q且为一*/
}
/*q作为局部变量,出花括号后q被销毁,同时也释放了q指向的空间*/
int foo = *p; // 操作undefined,p指向的空间被q释放掉了
//如果再删除p,会出现再次释放p指向的空间!即同一空间在这被释放了两次
所以shared_ptr智能指针用get函数时永远不要返回给其他的智能指针
unique_ptr
unique_ptr拥有它所指的对象。即一个对象在同一时间只能有一个unique_ptr指针
unique_ptr删除则unique_ptr所指对象销毁
声明:
unique_ptr<double> p1; // 指向类型为double的智能指针
unique_ptr<int> p2(new int(42)); //p2指向值为42的Int对象
unique_ptr是对象的 唯一智能指针,所以不支持unique_ptr指针间的拷贝和赋值
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1); //error:不能复制
unique_ptr<string> p3;
p3 = p2; //error:不能赋值
可以通过release和reset来改变对象的unique_ptr指针
//p1拥有的对象转移到p2
unique_ptr<string> p2(p1.release()); //release先返回p1的地址然后将p1置为null
unique_ptr<string> p3(new string("Trex"));
//p3拥有的对象转移到p2
p2.reset(p3.release()); //reset先释放了p2,然后p2获得p3的地址,p3被置为null
release要有指针接收其返回地址,否则自动释放智能指针指向对象
p2.release(); // wrong:p2没有销毁对象同时p2指针被置为null(尽量不要这样做!)
auto p = p2.release(); // ok,但是要记住删除p
unique_ptr能复制和赋值的条件是右值在复制和赋值后立刻被销毁,如函数返回值为unique_ptr
</pre><pre name="code" class="cpp"></pre><pre name="code" class="cpp">
unique_ptr<int> clone(int p) {
//ok,返回后会被销毁
return unique_ptr<int>(new int(p));
}
unique_ptr<int> clone(int p) {
unique_ptr<int> ret(new int (p));
// . . .
return ret;
}
C++primer描述使用动态内存不外乎这三个目的:
1. They don’t know how many objects they’ll need
2. They don’t know the precise type of the objects they need
3. They want to share data between several objects