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%安全吗?
答案 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
输出的最后一行是值三(如果它是是三)的事实不能证明该对象没有被删除。
取消引用指向已删除对象的指针是undefined behaviour,因此任何事情都可能发生。