智能指针详解,及面试常见问题
1.为什么要使用智能指针:
智能指针的作用是管理一个指针,因为使用裸指针存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏(还存在delete之后没有置为nullptr,造成指针悬空和野指针),使用智能指针可以很大程度上的避免这个问题,本质上智能指针就是一个类模板, 当超出了智能指针的作用域时,类会自动调用析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在析构函数中自动释放内存空间,不需要手动释放内存空间。智能指针是RAII机制的一种体现。
四种智能指针:
auto_ptr(c++98 提出,c++11 废弃,建议直接不学)。
int main(int argc , char * argv[])
{
std::auto_ptr<int> p1(new int(10));
std::auto_ptr<int> p2;
p2 = p1; // auto_ptr是所有权机制
std::cout<<*p2<<std::endl; // 10
std::cout<<*p1<<std::endl; // 段错误
return 0;
}
语法检测不会报错,p2剥夺了p1 的所有权,当程序运行时访问p1 将会报错。
auto_ptr 的缺点是:存在潜在的内存崩溃问题
unique_ptr(auto_ptr的优化)
unique_ptr 实现独占式拥有,保证同一时间内只有一个智能指针可以指向该对象。它对于避免内存泄露(例如“以new创建对象后因为发生异常而忘记调用delete”)特别有用。
unique_ptr采用所有权模式,还是上面那个例子
int main(int argc , char * argv[])
{
std::unique_ptr<int> p1(new int(10));
std::unique_ptr<int> p2;
// p2 = p1; 报错,非法操作
return 0;
}
编译器会认为p2=p1是非法操作,这样就避免了p1不再指向有效数据的问题。因此,unique_ptr比auto_ptr更安全。
另外 unique_ptr 还有更灵活的地方:当程序试图将一个 unique_ptr 赋值给另一个时,如果源unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做,比如:
unique_ptr<int> p1(new int (12));
unique_ptr<int> p2;
p2 = p1; //#1 不允许,因为p1将存在一段时间,p1是个左值
unique_ptr<int> p3;
p3 = unique_ptr<int>(new int(8)); //#2 允许,等号右边是临时右值
其中#1 会留下悬挂的p1,这可能导致危害(类似auto_ptr)。而#2 不会留下悬挂的 unique_ptr, 因为它调用 unique_ptr 的构造函数,该构造函数创建的临时对象在其所有权让给 p3 后就会被销毁。这种随情况而定的行为表明,unique_ptr 优于允许两种赋值的auto_ptr 。
注:如果确实想执行类似于#1 的操作,要安全的重用这种指针,可给它赋新值。C++有一个标准库函数std::move(),让你能够将一个 unique_ptr 赋给另一个。例如:
int main(int argc , char * argv[])
{
std::unique_ptr<int> p1, p2;
p1 = std::make_unique<int>(10);
p2 = std::move(p1);
p1 = std