c++ 智能指针 使用,常见问题,容器是否可以使用,多线程访问问题。

unique_ptr
说明:某个时刻只能有一个 unique_ptr 指向一个给定对象。
初始化:支持直接new化,不支持拷贝和赋值 操作。
unique_ptr<int> p1; // 指向一个double的unique_ptr
unique_ptr<int> p2(new int(42)); // p2指向一个值为42的int

由于一个 unique_ptr 拥有它指向的对象,因此 unique_ptr 不支持普通的拷贝或赋值操作
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2 (p1);    // 错误:unique_ptr 不支持拷贝
unique_ptr<string> p3;
p3 = p2; // 错误:unique_ptr不支持赋值

转移和释放
p3.reset();//释放p3指向的对象,将p3置为空
p3.release();//放弃对指针的控制权,返回指针,并将p3置为空,注意这里没有是否内存,而是返回了指针,需要外面释放
p3.release(); // 错误:p2不会释放内存,而且我们丢失了指针
auto p = p2.release(); // 正确,但我们必须记得 delete(p),返回是指针,不是智能指针。
p3= nullptr;//释放p3指向的对象,将p3置为空
p2.reset(p3.release()); // 将所有权从p3转移给p2 // reset 释放了 p2 原来指向的内存。
unique_ptr<string> upt1=std::move(upt);    // 控制权限转移
if(upt.get()!=nullptr) {                // 判空操作更安全

unique_ptr<int[]> p (new int[3]{1,2,3});  
p[0] = 0;// 重载了operator[]

p // 将p用作一个条件判断,若p指向一个对象,则为ture
*p // 解引用p,获得它指向的对象
p->mem // 等价于(*p).mem
p.get() // 返回p中保存的指针
swap(p,q) // 交换p和q中的指针
p.swap(q)

例外情况:不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的 unique_ptr。最常见的例子是从函数返回一个unique_ptr:

//返回一个局部对象的拷贝:
unique_ptr<int> clone (int p) 
{
    unique_ptr<int> ret(new int (p));
    //… 
    return ret;
}

unique_ptr<int> p = close(5);
编译器都知道要返回的对象将要被销毁。在此情况下,编译器执行一种特殊的“拷贝”,在《C++ Primer》13.6.2节(第473页)中有介绍


shared_ptr
说明:允许多个shared_ptr类型指针指向同一个对象
初始化:
shared_ptr<string> p1;//空指针
shared_ptr<list<int>> p1;//
shared_ptr<int> p2(new int (42)); // p2 指向一个值为 42 的 int
shared_ptr<int> pi = new int (1024); // 错误:必须使用直接初始化形式,接受指针参数的智能指针构造函数是 explicit 的。因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针
shared_ptr<int> p3 = make_shared<int>(42);
auto p = make_shared<vector>();// p6指向一个动态分配的空vector<string>
auto q(p); // p和q指向相同对象,此对象有两个引用者
q=p;//递增q指向的对象的引用计数和更改q指针, 递减r原来指向的对象的引用计数,r原来指向的对象已没有引用者,会自动释放


出于相同的原因,一个返回 shared_ptr 的函数不能在其返回语句中隐式转换一个普通指针:

shared_ptr<int> clone(int p)
{
    return new int(p); // 错误:隐式转换为 shared_ptr<int>
}
我们必须将 shared_ptr 显式绑定到一个想要返回的指针上:

shared_ptr<int> clone(int p)
{
    return shared_ptr<int>(new int(p)); // 正确:显式地用int*创建shared_ptr<int>
}
p // 将p用作一个条件判断,若p指向一个对象,则为ture
*p // 解引用p,获得它指向的对象
p->mem // 等价于(*p).mem
p.get() // 返回p中保存的指针
swap(p,q) // 交换p和q中的指针
p.swap(q)
常见使用错误:
1)使用一个内置指针来访问一个智能指针所负责的对象是很危险的,因为我们无法知道对象何时会被销毁
//在函数被调用时 ptr 被创建并初始化
void process(shared_ptr<int> ptr)
{
    //使用ptr
}//ptr离开作用域,被销毁

int main()
{
    shared_ptr<int> p( new int (42) ) ; //引用计数为 1
    process (p);//拷贝p会递增它的引用计数;在process中引用计数值为2
    int i = *p; //正确:引用计数值为1    
}
下面考虑混合使用普通指针和智能指针的情况。虽然不能传递给 process —个内置指针,但可以传递给它一个(临时的) shared_ptr,这个 shared_ptr 是用一个内置指针显式构造的。但是,这样做很可能会导致错误:

int *x(new int(1024));    // 危险:x是一个普通指针,不是一个智能指针
process (x);// 错误:不能将 int*转换为一个 shared_ptr<int> 
process ( shared_ptr<int> (x) ); // 合法的,但内存会被释放! 
int j = *x; // 未定义的:x是一个空悬指针!
在上面的调用中,我们将一个临时 shared_ptr 传递给 process。当这个调用所在的表达式结束时,这个临时对象就被销毁了。销毁这个临时变量会递减引用计数,此时引用计数就变为 0 了。因此,当临时对象被销毁时,它所指向的内存会被释放。但 x 继续指向(已经释放的)内存,从而变成一个空悬指针。如果试图使用 x 的值,其行为是未定义的

例如下面代码会导致堆内存破坏而引起程序奔溃
   void test_boost_shared_ptr_crash()
   {
        Foo* pFoo = new Foo("Foo1");
        boost::shared_ptr<Foo> ptr1(pFoo);
        boost::shared_ptr<Foo> ptr2(pFoo);
   }   
  上述代码两次释放同一内存而破坏堆,导致程序奔溃。
  
  

weak_ptr
说明:weak_ptr 是一种不控制所指向对象生存期的智能指针,它指向由一个 shared_ptr 管理的对象 将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数。一旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。即使有 weak_ptr 指向对象,对象也还是会被释放,因此,weak_ptr 的名字抓住了这种智能指针 “弱” 共享对象的特点
说明2:弱智者设计是为了,解决shared_ptr 环引用问题,无法释放类,导致内存泄漏问题。A成员有B,B的成员有A。这样就无法释放A,B内存。
初始化:
weak_ptr<T> w // 空weak_ptr可以指向类型为T的对象
weak_ptr<T> w(sp) // 与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的S型
w = p // p可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象
w.reset() // 将W置为空
w.use_count() // 与w共享对象的shared ptr的数量
w.expired()    // 若 w.use_count()为0,返回true,否贝y返回 false
w.lock() // 如果expired为true,返回一个空shared ptr:否则返回一个 指向w的对象的shared_ptr
auto p = make_shared<int>(42);
weak_ptr<int> wp(p); // wp弱共享p; p的引用计数未改变
if ( shared_ptr<int> np = wp.lock() )

p // 将p用作一个条件判断,若p指向一个对象,则为ture
*p // 解引用p,获得它指向的对象
p->mem // 等价于(*p).mem
p.get() // 返回p中保存的指针
swap(p,q) // 交换p和q中的指针
p.swap(q)

auto_ptr
说明:禁用,copy,赋值的时候权限转移,没有编译报错,容易使用错误。替代品:unique_ptr

容器使用说明:
vector,list等容器   unique_ptr 不可使用。因为vector在调整大小的时候,会从新copy内容,而unique_ptr不支持copy,编译会报错。其他智能指针可以使用容器。

多线程使用说明:
多线程读写访问内容,需要加锁。shared_ptr 不同的实例,可以多线程独立的多线程访问。但是要读写实体内容的时候,需要加锁

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值