智能指针与异常
如果使用智能指针, 如果程序块过早的结束, 智能指针能保证在内存不再需要时进行释放. (特别是在有多个出口的函数中 -- 虽然应尽量避免设计这样的函数, 但凡事总有例外 -- 此时使用智能指针来自动释放内存是非常方便的)
对于异常处理来说, 考虑下面两个函数, 当程序发生异常时, 智能指针也能正确的释放内存.
void f3()
{
int* p = new int(10);
throw "some error infomations";
delete p;
}void f4()
{
std::shared_ptr<int> sp = std::make_shared<int>(10);
throw "some error infomations";
} 使用智能指针时的注意事项
C++智能指针使用时需要注意的事项, C++11中已经废弃了 auto_ptr, 因此不再讨论其用法, 无特殊说明, 下面的事项对 auto_ptr 而言, 可能是不正确的.(1) 不要把一个原生指针给多个智能指针对象管理, 对所有的智能指针对象都成立 int* p = new int(2);
std::shared_ptr<int> sp0(p);
std::shared_ptr<int> sp1(p); // 错误, 不能将同一原始指针对象给两个智能指针对象管理(2) 不要把 this 指针给智能指针对象, 对所有的智能指针对象(包括 auto_ptr)都成立, 下面的代码演示错误的使用方法 #define PRINT_FUN() printf("%s:%d
", __FUNCTION__, __LINE__)class CTest{public:CTest(){};~CTest(){PRINT_FUN();};void Run(){m_sp = std::shared_ptr<CTest>(this); // 错误, 当 CTest 对象释放时也会释放 m_sp , 此时会再次 delete CTest 对象. (析构函数中的打印消息可以看出会出现一个对象两次调用析构函数.)}private:std::shared_ptr<CTest> m_sp;};std::shared_ptr<CTest> sp(new CTest());sp->Run();或者这样写CTest t;t.Run(); (3) 不要在函数实参里创建智能指针对象function ( shared_ptr<int>(new int), g( ) ); //有缺陷
可能的过程是先 new int, 然后调 g( ), g( )发生异常, shared_ptr<int> 没有创建, int内存泄露
推荐写法:
shared_ptr<int> p(new int());
f(p, g());(4) 处理不是 new 创建的对象要小心. 如果确实需要这样做, 需要智能指针传递一个删除器, 自定义删除行为. int* pi = (int*) malloc(4);
shared_ptr<int> sp(pi); // shared_ptr 析构时将调用 delete. 使用 malloc 分配内存, 用 delete 释放显然不对. (5) 不要使用 new 创建一个智能指针对象.如 new shared_ptr<T> : 本来 shared_ptr 就是为了管理指针资源的, 不要又引入一个需要管理的指针资源shared_ptr<T>* (6) 使用 dynamic_pointer_cast 进行转换(C++11 中已废弃 shared_dynamic_cast)class B{public:B(){};virtual ~B(){};};class D : public B{public:D(){};virtual ~D(){};};std::shared_ptr<B> sp(new D);B* b = sp.get();D* d = dynamic_cast<D*>(b);正确用法:std::shared_ptr<B> spb(new D);std::shared_ptr<D> spd = std::dynamic_pointer_cast<D>(spb); (7) 不要 memcpy 智能指针对象shared_ptr<B> sp1(new B);
shared_ptr<B> sp2;
memcpy(&sp2, &sp1, sizeof(shared_ptr<B>)); //sp2.use_count()==1
很显然,不是通过正常途径(拷贝构造,赋值运算),引用计数是不会正确增长的。(8) 智能指针对象数组的使用, 需要自定义释放器. shared_ptr 数组, std::shared_ptr<A> p(new A[10], std::default_delete<A[]>());
std::unique_ptr<int[]>(new int[10], std::default_delete<int[]>()); (9) 将智能指针对象作为函数参数传递时要小心, 如下面的代码, 当调用所在的表达式结束(即函数调用返回)时, 这个临时对象就被销毁了, 它所指向的内存也被释放. int* pa = new int(10); // 小心, 不是一个智能指针
f(std::shared_ptr<int>(pa)); // 合法的, 但内存会被释放
int a = *pa; // 错误, pa已经被释放, 但继续指向已经释放的内存, 从而变成了一个空悬指针, 现在试图访问 pa 的值, 其结果是未定义的
应该这样使用:
std::shared_ptr<int> sp(new int(10));
f(std::shared_ptr<int>(sp)); // 调用拷贝构造函数, sp.use_count == 2 (10) 当将一个智能指针对象(如 shared_ptr)绑定到一个普通指针时, 就将内存管理的责任交给了这个 shared_ptr. 此后就不应该使用内置指针来访问 shared_ptr 所指向的内存了. (11) 不能使用 delete 释放 get 返回的普通指针. get 函数的设计是为了向不能使用智能指针的代码传递一个普通指针, 应该减少 get 函数的调用. (12) 不要使用 get 返回的普通指针来初始化另一个智能指针, 或为另一个智能指针赋值. 显然如果这样做, 将导致两次释放相同的内存, 或者其中一个已经将内存释放, 但另一个还在使用.std::shared_ptr<int> sp = std::make_shared<int>(10);
int* p = sp.get();
{
std::shared_ptr<int> sp(p);
}
int x = *sp;本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138000.htm