由于动态内存使用很容易出问题,例如忘记了释放内存造成内存泄漏,释放正在使用的内存造成非法内存访问等,为了更容易和安全地使用动态内存,标准库提供了三种智能指针来管理动态对象,shared_ptr允许多个智能指针指向同一个对象,unique_ptr则独占所指向的对象,weak_ptr是一种弱引用,指向shared_ptr所管理的对象。
智能指针也是模板,当我们创建智能指针时,必须提供指针可以指向的类型。智能指针的使用方式与普通指针类似,解引用一个智能指针返回它指向的对象,条件判断中使用智能指针的效果就是检测它是否为空。
shared_ptr
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。
int main()
{
shared_ptr p = make_shared(2);
if (p) {
cout << *p << endl;
}
auto str = make_shared(8, '6');
cout << *str << endl;
system("pause");
}
当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其它shared_ptr指向相同的对象,当引用计数为0时,shared_ptr会自动释放自己管理的对象。
int main()
{
shared_ptr p = make_shared(2);
if (p.unique()) {
cout << "唯一的" << endl;
}
//返回指向对象的shared_ptr数量
cout << p.use_count() << endl;
auto a = p;
cout << p.use_count() << endl;
system("pause");
}
我们还可以使用new返回的指针来初始化智能指针,接受指针参数的构造函数是explicit的,必须使用直接初始化来初始化一个智能指针。
//正确
shared_ptr p1(new int(33));
//错误,必须使用直接初始化,接受指针参数的构造函数是explicit的
shared_ptr p2=new int(44);
由于shared_ptr会自动释放内存,所以不要混用普通指针和智能指针,否则可能导致错误。
void printInt(shared_ptr p)
{
cout << *p << endl;
}
int main()
{
auto p = new int(22);
printInt(shared_ptr(p));//内存会被释放
int i = *p;//错误,p指向的内存已经被释放
cout << i << endl;//i值不为22
system("pause");
}
智能指针定义了一个名为get的函数返回原始指针,只有你确定不会delete指针的情况下才能使用get,尤其是永远也不要用get初始化另一个智能指针或为另一个智能指针赋值。
int main()
{
auto p = make_shared(22);
cout << *(p.get()) << endl;
system("pause");
}
与赋值类似,reset可以将管理的指针置空或使之指向另外一个指针,并更新引用计数。
int main()
{
auto p = make_shared(22);
p.reset();
cout << p.use_count() << endl;
cout << p.get() << endl;
p.reset(new int(33));
cout << *p << endl;
system("pause");
}
默认情况下,当一个shared_ptr要销毁它指向的对象时,会执行delete操作,我们也可以使用自定义的函数代替delete。
class MyClass
{
};
void myDelete(MyClass* obj)
{
cout << "my delete" << endl;
delete obj;
}
void testFunc()
{
auto obj = shared_ptr(new MyClass(), myDelete);
obj.reset(new MyClass(), myDelete);
}
int main()
{
testFunc();
system("pause");
}
unique_ptr
和shared_ptr不同,同一时刻只能有一个unique_ptr指向给定的对象,当unique_ptr被销毁时,它所指向的对象也随之销毁,unique_ptr不支持拷贝和赋值。
unique_ptr大部分操作和shared_ptr类似,只是如果想要替换默认delete方法,需要在创建时提供替换函数的类型。
class MyClass
{
};
void myDelete(MyClass* obj)
{
cout << "my delete" << endl;
delete obj;
}
void testFunc()
{
auto obj = unique_ptr(new MyClass(), myDelete);
}
int main()
{
testFunc();
system("pause");
}
weak_ptr
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。
int main()
{
auto p = make_shared(33);
weak_ptr weakValue = p;
//与weak_ptr共享对象的shared_ptr的数量
cout << weakValue.use_count() << endl;
//测试use_count是否为0
cout << weakValue.expired() << endl;
//如果expired为true,则返回空指针,否则返回一个指向对象的shared_ptr
if (auto newValue = weakValue.lock()) {
cout << newValue << endl;
}
system("pause");
}
智能指针和异常
由于在栈上分配的对象会自动销毁,即使中途发生异常,所以智能指针也能利用这一特性确保异常发生后对象能正常释放。
class MyClass
{
public:
~MyClass() { cout << "MyClass Destory..." << endl; }
};
void testFunc()
{
MyClass obj1;
auto obj2 = make_shared();
throw exception();
}
int main()
{
try{
testFunc();
}catch(...){
cout << "catch exception..." << endl;
}
system("pause");
}