1. 传统指针存在的问题
传统指针存在诸多的问题,比如指针所指向的对象的生命周期问题,挂起引用(dangling references),以及内存泄露(memory leaks).
如下是一个传统指针的使用过程
void Foo() {
int *iPtr = new int[5];
// manipulate the memory block
// ...
// ...
// ...
delete[] iPtr;
}
以上代码将正常运行且内存将被合理释放,但是使用指针常会发生一些意想不到的事情,比如访问一个非法的内存单元,除0操作,以及根据一些判断条件处理的返回return 语句。
2. 什么是智能指针(Smart Pointer)
智能指针是RAII(Resource Acquisition is initialization)用来动态的分配内存。它提供了普通指针的所有接口外加少数异常处理。在构造阶段,它将分配内存,而在非其作用域内将自动释放所占有的内存。
在C++98中,使用 auto_ptr
来解决上述问题。
2.1 auto_ptr
#include <iostream>
#include <memory>
using namespace std;
class Test {
public:
Test(int a = 0) : m_a(a) {}
~Test() {
cout << "Calling destructor" << endl;
}
public:
int m_a;
};
int main()
{
auto_ptr<Test> p(new Test(5));
cout << p->m_a << endl;
return 0;
}
输出结果:
上述代码将智能的释放相关的内存。
#include <iostream>
#include <memory>
using namespace std;
class Test {
public:
Test(int a = 0) : m_a(a) {}
~Test() {
cout << "Calling destructor" << endl;
}
public:
int m_a;
};
void Fun()
{
int a = 0, b = 5, c;
if(a == 0) {
throw "Invalid divisor";
}
c = b / a;
return;
}
int main()
{
try {
auto_ptr<Test> p(new Test(5));
Fun();
cout << p->m_a << endl;
}
catch(...) {
cout << "Something has gone wrong" << endl;
}
return 0;
}
在上述代码中,即使异常抛出,指针照样被正常释放。这是因为当异常抛出时,栈松绑(stack unwinding)。 当所有属于try block
的本地对象被销毁时,指针p
不在作用域中而被释放。
问题1.
至少从目前来说auto_ptr
是智能的。但是它有一个非常本质的缺点:auto_ptr
会传递它本身的ownership当其被赋值给另一个auto_ptr
对象。正如下述程序所示,一个auto_ptr
对象传递给函数Fun()
中的auto_ptr
对象时,其ownership,或者说是smartness将不再返回给原auto_ptr
所指向的p。
#include <iostream>
#include <memory>
using namespace std;
class Test {
public:
Test(int a = 0) : m_a(a) {}
~Test() {
cout << "Calling destructor" << endl;
}
public:
int m_a;
};
void Fun(auto_ptr<Test> p1)
{
cout << p1->m_a << endl;
cout << "Fun() end" << endl;
}
int main()
{
auto_ptr<Test> p(new Test(5));
Fun(p);
cout << p->m_a << endl;
return 0;
}
运行结果:
以上程序将crash因为存在野指针auto_ptr
。上述代码奔溃的主要原因是,原先的p
占有对其自身分配内存的管理权。然而通过Fun()
函数将其管理权转给p1
,此时因为p1
的smartness,在其结束时将释放其所指向的内存块。而此时原先的p
将再拥有任何内存,而导致在访问时出现了空指针,野指针的引用问题。
问题2.
auto_ptr
不能使用于数组对象。 这里的意思是不能使用于操作符new[]
。
int main()
{
auto_ptr<Test> p(new Test[5]);
return 0;
}
上述代码将runtime error。因为对于auto_ptr
而言,其调用的是delete
而非delete []
。
问题3.
auto_ptr
不能使用于一些标准的容器库。比如vector
,list
,map
等等。
C++11提出了新型的智能指针,并且都赋予了其相应的意图。
2.2 shared_ptr
未完待续…
版权声明:本文为博主原创文章,未经博主允许不得转载。