前言
下面简单的概括了 3中智能指针的在使用时候需要注意的一些地方,三种智能指针在离开其作用域之后都会被自动释放,适合有一定基础。
提示:以下是本篇文章正文内容,下面案例可供参考
shared_ptr
shared_ptr使用注意点:
- shared_ptr 不能通过“直接将原始这种赋值”来初始化,需要通过构造函数和辅助方法来初始化
#include <iostream>
using namespace std;
int main()
{
//正确初始化方法
std::shared_ptr<int> p1(new int(1));
//错误的初始化方法-使用直接将原始这种赋值
std::shared_ptr<int> p1 = new int(1);
}
- 每次调用构造函数来初始化指针时,会引起引用计数加1
- 每次调用构造函数来删除指针时,也会引起引用计数减1
#include <iostream>
using namespace std;
int main()
{
std::shared_ptr<int> p1(new int(1));
std::shared_ptr<int> p2(p1);
//查看引用计数
cout << "p1.use_count() = " << p1.use_count() << endl;
cout << "p2.use_count() = " << p2.use_count() << endl;
//调用构造删除删除 p2 指针
p2.reset();
//查看引用计数
cout << "p1.use_count() = " << p1.use_count() << endl;
cout << "p2.use_count() = " << p2.use_count() << endl;
}
- 通过 get 方法来返回原始指针(不建议 (1)使用无论是保存为裸指针还是shared_ptr都是错的 (2)delete
p.get()会造成一块内存delete两次))
#include <iostream>
using namespace std;
int main()
{
std::shared_ptr<int> p1(new int(1));
//错误示例:保持了裸指针且不小心删除了,会造成一块内存删除两次,程序卒
int *p = p1.get();
delete p;
- 不要用一个原始指针初始化多个shared_ptr
#include <iostream>
using namespace std;
int main()
{
//错误示例——一个原始指针初始化多个shared_ptr
int* p = new int(1);
std::shared_ptr<int> p1(p);
std::shared_ptr<int> p2(p); //这样子是错的
//查看引用计数
cout << "p1.use_count() = " << p1.use_count() << endl;
cout << "p2.use_count() = " << p2.use_count() << endl;
while (1)
{
}
//如果 退出了shared_ptr 的作用域,也会发生一块内存被 删除了两次,程序卒。
}
- 不要在函数实参中创建shared_ptr
因为C++的函数参数的计算顺序在不同的编译器不同的约定下可能是不一样的,一般是从右到左,但也
可能从左到右,所以,可能的过程是先new int,然后调用g(),如果恰好g()发生异常,而shared_ptr还
没有创建, 则int内存泄漏了,正确的写法应该是先创建智能指针,代码如下:
function(shared_ptr<int>(new int), g()); //有缺陷
shared_ptr<int> p(new int);
function(p, g());
- 函数想返回 shared_ptr 指针时,不能将this指针作为shared_ptr返回出来,因为this指针本质上是一个裸指针,因此,这样可能会导致重复析构。
错误示例:
#include <iostream>
using namespace std;
class A
{
public:
shared_ptr<A> GetSelf()
{
return shared_ptr<A>(this);
}
~A()
{
cout << "Deconstruction A" << endl;
}
};
int main()
{
shared_ptr<A> sp1(new A);
shared_ptr<A> sp2 = sp1->GetSelf();
return 0;
}
程序输出:
Deconstruction A
Deconstruction A
正确示例:
#include <iostream>
using namespace std;
class A : public std::enable_shared_from_this<A>
{
public:
shared_ptr<A>GetSelf()
{
return shared_from_this(); //
}
~A()
{
cout << "Deconstruction A" << endl;
}
};
int main()
{
shared_ptr<A> sp1(new A);
shared_ptr<A> sp2 = sp1->GetSelf();
return 0;
}
除此之外还需注意避免循环引用而导致内存泄露
#include <iostream>
using namespace std;
class A;
class B;
class A
{
public:
shared_ptr<B> bPtr;
~A()
{
cout << "Deconstruction A" << endl;
}
};
class B
{
public:
shared_ptr<A> aPtr;
~B()
{
cout << "Deconstruction B" << endl;
}
};
int main()
{
{
std::shared_ptr<A> ap(new A);
std::shared_ptr<B> bp(new B);
ap->bPtr = bp;
bp->aPtr = ap;
}
// 循环引用导致ap bp退出了作用域都没有析构
cout << "main leave " << endl;
}
unique_ptr
独占共享指针
注意点:
- 不允许其他智能指针共享其内部指针,不允许将一个unique_ptr 赋值给另外的智能指针
#include <iostream>
using namespace std;
int main()
{
std::unique_ptr<int> ptr(new int(10));
std::shared_ptr<int[]> ptr2;
ptr2 = ptr; // 错误:不能这样写
}
- 不允许赋值给其他指针但是可以通过实体店std::move转移到其他的unique_ptr,不过这样它本身就不享有原来指针的使用权了
#include <iostream>
using namespace std;
int main()
{
std::unique_ptr<int[]> ptr(new int[10]);
std::shared_ptr<int[]> ptr2;
ptr[9] = 9;
ptr2 = std::move(ptr); //ptr原来的指针的使用权交给ptr2
if (!ptr )
{
cout << "ptr is null" << endl;
}
cout << "ptr2[9] = " << ptr2[9] << endl;
}
- 和 shared_ptr 不一样的是,unique_ptr 需要指定删除器的时候需要在声明的时候指明
#include <iostream>
using namespace std;
int main()
{
std::unique_ptr<int[]> ptr(new int[10]);
std::shared_ptr<int[]> ptr2(new int[10]);
//std::shared_ptr<int> ptr3(new int(1), [](int* p) {delete p; }); // 正确
//std::unique_ptr<int> ptr4(new int(1), [](int* p) {delete p; }); // 错误
std::unique_ptr<int, void(*)(int*)> ptr5(new int(1), [](int* p) {delete p; }); // 正确
}
weak_ptr
weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引shared_ptr,weak_ptr只是提供了对管理对象的一个访问手段。该指针设计的目的就是为了解决shared_ptr 相互引用时的死锁问题,因为该指针不会增加指针的引用,它是对对象的一种弱引用和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
使用注意点:
- 通过expired 方法判断所观察资源是否已经释放
#include <iostream>
using namespace std;
int main()
{
std::shared_ptr<int> ptr(new int(10));
std::weak_ptr<int> ptr2 = ptr;
if ( !ptr2.expired())
{
cout << "ptr2 所监视指针ptr 没有被释放" << endl;
}
}
- 通过lock方法获取监视的shared_ptr 指针
#include <iostream>
using namespace std;
int main()
{
std::shared_ptr<int> ptr(new int(10));
std::weak_ptr<int> ptr2 = ptr;
ptr.reset();
if( ptr2.expired())
{
std::cout << "ptr2 所监视指针ptr 被释放" << endl;
}
}
- 在使用weak_ptr是需要调用expired 方法判断指针是否有效,不然有可能对象资源已经被释放
#include <iostream>
using namespace std;
int main()
{
std::shared_ptr<int> ptr(new int(10));
std::weak_ptr<int> ptr2 = ptr;
//weak_ptr不能直接 *ptr
//*ptr2 = 1; //错误
*ptr2.lock() = 1;
if( !ptr2.expired())
{
std::cout << "ptr2 指向对象的值为: " << *ptr2.lock();
}
}
使用智能指针安全吗?
- 在多线程的使用中,如果多个线程使用同一个shared_ptr的对象时是不安全的。如果在某一个线程中删除了该对象,其他线程访问的时候就会访问到一个被释放的内存而造成程序崩溃
- 如果每个线程都有一个独立的shared_ptr,共同管理一个同一份数据,不会出现上面的情况,程序不会崩溃。但是如果有其它线程对数据进行修改的话,其指向的数据也是会被修改的
结束啦