智能指针背后的思想
- 普通指针的弊端:delete不被执行,忘了释放内存,导致内存泄漏
- 如果在对象过期时,让它的析构函数删除指向的内存,这正是auto_ptr , unique_ptr , shard_ptr背后的思想
使用
模板类auto_ptr
template<class x> class auto_ptr{
public:
explicit auto_ptr(x* p = 0) throw();
...
}
auto_ptr<double> pd(new double);
//pd指向double的一个智能指针,new double 替代 double *pd
auto_ptr<string> pd(new string);
//new string 替代 string *pd
- new double 是new返回的指针,指向新分配的内存块
- 可以用*Pd 解除引用操作,访问结构成员(pd->name)
注意事项
问题
auto_ptr<string> ps(new string("I WIN!"));
auto_ptr<strng> vocation;
vocation = ps;
- 两个智能指针都指向一个string对象,ps过期和vocation过期时,会试图删除同一个对象两次
方法
-
定义赋值运算符,让其执行深复制,这样两个指针将指向不同的对象,其中的一个对象时另一个对象的副本
-
对于对象,只能有一个智能指针拥有它。这样只有拥有对象的智能指针的构造函数才会删除该对象。
-
然后,可以让赋值操作符转让所有权
-
auto_ptr 和 unique_ptr 就是这样的策略
-
auto_ptr
-
auto_ptr<string> p1(new string("I WIN!")); auto_ptr<strng> p2; p2 = p1;
- p2接管string对象的所有权时,p1的所有权将被剥夺,虽然可以防止p1删除string对象。防止删除同一个对象两次
- 但如果试图使用p1,这是件坏事,p1不再指向有效的数据
-
unique_ptr
-
unique_ptr<string> p3(new string("I WIN!")); unique_ptr<strng> p4; p4 = p3;
- 编译不通过,第3行报错,避免了访问p3,而p3不再指向有效数据的问题。
- 因此unique_ptr 比auto_ptr更安全
- 编译阶段比潜在的程序崩溃更安全
-
而以下编译通过,可以运行
-
unique_ptr<strng> p4; p4 = unique_ptr<string>(new string("I WIN!");
-
因为是个临时右值
-
-
使用new分配内存,才能使用auto_ptr 和 shared_ptr ,使用new[] 不能使用它们
- 而不使用new分配内存时,不能使用它们,必须要用new分配,才能使用
-
unique_ptr只能使用new 和 new[]分配内存
-
-
引用计数,例如:赋值时,计数将加1,而指针过期时,计数将减1,。仅当最后一个指针过期时,才调用delete,这是share_ptr的策略
- 适用于程序要使用多个指向同一对象的的指针。
- 当unique_ptr 为右值时,可以将其赋给shared_ptr,shared_ptr将接管原来归unique_ptr的对象
//===============================================================
//FileName:
// smrtptrs.cpp
//Date:
// 2019/11/25
//Author:
// khoing(https://blog.csdn.net/qq_45391763)
//===============================================================
// smrtptrs.cpp -- using three kinds of smart pointers
#include <iostream>
#include <string>
#include <memory>//使用智能指针必须包含
class Report
{
private:
std::string str;
public:
Report(const std::string s) : str(s) { //相当于this.s = str
std::cout << "Object created!\n";
}
~Report() {
std::cout << "Object deleted!\n";
}
void comment() const {
std::cout << str << "\n";
}
};
int main()
{
{
std::auto_ptr<Report> ps(new Report("using auto_ptr"));
ps->comment(); // use -> to invoke a member function
}
{
std::shared_ptr<Report> ps(new Report("using shared_ptr"));
ps->comment();
}
{
std::unique_ptr<Report> ps(new Report("using unique_ptr"));
ps->comment();
}
// std::cin.get();
return 0;
}
// fowl.cpp -- auto_ptr a poor choice
#include <iostream>
#include <string>
#include <memory>
int main()
{
using namespace std;
auto_ptr<string> films[5] =
{
auto_ptr<string> (new string("Fowl Balls")),
auto_ptr<string> (new string("Duck Walks")),
auto_ptr<string> (new string("Chicken Runs")),
auto_ptr<string> (new string("Turkey Errors")),
auto_ptr<string> (new string("Goose Eggs"))
};
auto_ptr<string> pwin;
pwin = films[2]; // films[2] loses ownership
cout << "The nominees for best avian baseball film are\n";
for (int i = 0; i < 5; i++)
cout << *films[i] << endl;
cout << "The winner is " << *pwin << "!\n";
// cin.get();
return 0;
}