问题描述
在g ++ 4.8.5编译下,发现对sharedptr的不当使用会导致对shared_ptr的多次破坏。
假码:
#include<memory>
class Demo
{
public:
~Demo()
{
// Do something and cost some milliseconds
}
};
typedef std::shared_ptr<Demo> DemoPtr;
DemoPtr global_demo;
DemoPtr instance() {return global_demo;}
// Main thread
int main()
{
global_demo = std::make_shared<Demo>();
// Do something
}
// Thread A
void thread_func()
{
// Do something
if(instance() != nullptr)
{
// Do something
}
// Do something
}
当主线程结束时,global_demo引用计数减少为0,并且global_demo开始被破坏。销毁global_demo时,线程A调用instance()进行判断,这导致global_demo的引用计数再次增加一,然后释放局部变量时,引用计数再次减小为0,从而导致对global_demo指向的对象的销毁。再次调用该函数。
查看gcc源代码:
//*************__shared_count***************//
__shared_count&
operator=(const __shared_count& __r) noexcept
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
{
if (__tmp != 0)
__tmp->_M_add_ref_copy();
if (_M_pi != 0)
_M_pi->_M_release();
_M_pi = __tmp;
}
return *this;
}
//************_Sp_counted_base*****************//
void
_M_add_ref_copy()
{ __gnu_cxx::__atomic_add_dispatch(&_M_use_count,1); }
那么,这是一个GCC错误吗?
在这种情况下,我应该使用std :: weak_ptr解决此问题吗? 那么,我的instance()方法代码是这样的吗?
DemoPtr instance()
{
std::weak_ptr<Demo> w(global_demo);
if(!w.expired())
{
return w.lock();
}
return nullptr;
}
解决方法
那么,这是一个GCC错误吗?
不。这是程序中的错误:
global_demo被破坏
线程A调用instance()
DemoPtr instance() {return global_demo;}
您正在复制生命周期已结束(被破坏)的对象的副本(return global_demo;
)。该程序的行为是不确定的。
在这种情况下,我应该使用std :: weak_ptr解决此问题吗?
这不能修复该错误。您必须做的是在从main
返回之前,加入所有依赖静态变量的线程。 从技术上讲,可以在静态对象的析构函数中在main
返回之后加入线程,只要保证该对象在依赖的静态对象之前被销毁即可。但是,祝你好运。
对于某些线程,我无法控制结束。
然后,您必须避免在那些线程中使用任何静态变量。在示例情况下,创建global_demo
的线程本地副本,并在线程内使用它。