在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
的线程本地副本,并在线程中使用该副本。