C ++为什么原始指针不会增加shared_ptr的引用计数?

时间:2018-07-29 07:44:20

标签: c++ c++11

shared_ptr使用引用计数来确定何时销毁对象。 请看一下这段代码:

int main() {
    std::shared_ptr<int> pt = std::make_shared<int>(3);
    int *pt2 = pt.get();
    cout << "reference count " << pt.use_count() << endl;
    pt = 0;
    cout << *pt2;

};

将pt设置为0后,引用计数应变为0,并且对象应销毁。但是我仍然可以使用pt2来访问它。就我而言,结果是正确的,但我想那只是运气。那么,这是否意味着如果程序员想做一些愚蠢的事情,引用计数机制仍然不能使它100%安全吗?

2 个答案:

答案 0 :(得分:4)

shared_ptr的工作方式不是这样。 从第一个指针生成新的共享指针时,计数会增加。 get只是处理只能采用原始指针的旧代码的一种方法。 通过使用get,您正在破坏智能指针的安全性。

换句话说,get中的指针仅适合作为观察者,而不适合作为所有者,并且在您确实需要原始指针时也是如此。 如果您只需要观察者,请使用weak_ptr

的确,原则上get可以在拥有所有权的情况下增加计数,但仍不清楚何时再次减少计数。 提取原始指针后,将无法返回到原始计数器。

除非您知道自己在做什么,否则请不要使用get

它是这样工作的:

#include<iostream>
#include<memory>

using std::cout; using std::endl;

int main(){

    std::shared_ptr<int> pt = std::make_shared<int>(3);
    assert(pt.use_count() == 1);
    std::shared_ptr<int> pt2 = pt;
    assert(pt.use_count() == 2);
    assert(pt2.use_count() == 2);
    pt.reset(); // or pt = 0;
    assert(pt.use_count() == 0);
    assert(pt2.use_count() == 1);
    assert(*pt2 == 3);
    assert(!pt);

    return 0;
}

答案 1 :(得分:3)

  

将pt设置为0后,引用计数应变为0,并销毁对象

引用计数确实变为零,并且对象被销毁。

int替换为您自己的类MyInt,以查看被调用的构造函数和析构函数...

class MyInt
{
private:
   int val;

public:
   MyInt() : val(0)          { std::cout << "default c'tor called" << std::endl; }
   MyInt(int rhs) : val(rhs) { std::cout << "c'tor (" << rhs << ") called" << std::endl; }
   ~MyInt()                  { std::cout << "d'tor called" << std::endl; }
   int getval (void)         { return val; }
};

…然后更新main()

int main()
{
   std::shared_ptr<MyInt> pt = std::make_shared<MyInt>(3);

   MyInt* pt2 = pt.get();

   std::cout << "reference count " << pt.use_count() << std::endl;

   pt = 0;

   std::cout << pt2->getval() << std::endl;

   return 0;
}

输出(可能)是这样的...

  

c'tor(3)被称为
  参考计数1
  d'tor叫
  3

runnable sample

输出的最后一行是值三(如果它是三)的事实不能证明该对象没有被删除。

取消引用指向已删除对象的指针是undefined behaviour,因此任何事情都可能发生。