我可以使用placement new来重置shared_ptr中的对象吗?

Nat*_*mal 8 c++ memory performance

假设我有一堂课.

class BigData {...};
typedef boost::shared_ptr<BigData> BigDataPtr; 
Run Code Online (Sandbox Code Playgroud)

然后我做:

BigDataPtr bigDataPtr(new BigData());
Run Code Online (Sandbox Code Playgroud)

在我完成了我的对象之后,我确信没有其他用户使用该对象.

执行以下操作是否安全:

bigDataPtr->~BigDataPtr();
new (&*bigDataPtr) BigData;
Run Code Online (Sandbox Code Playgroud)

这会让我重置对象而不需要任何额外的分配吗?

Jon*_*rdy 6

有几种方法可以解决这个问题.您可以使用新的展示位置,这可以保证安全,原因有两个:

  1. 您已经为对象分配了内存,因此您知道它的大小和对齐方式正确.

  2. shared_ptr是非侵入性的; 它的唯一责任是计算参考资料并在必要时致电删除者.

但是,请考虑如果对象的重建失败会发生什么 - 即抛出异常:

bigDataPtr->~BigDataPtr();
new (bigDataPtr.get()) BigData;
Run Code Online (Sandbox Code Playgroud)

然后你有一个问题:可以在非构造对象上调用删除器,几乎肯定会导致未定义的行为.我说"差不多",因为删除者可能是一个无操作,在这种情况下一切都会很好.

我认为更安全的是将新值移动到现有对象中:

*bigDataPtr = BigData(42);
Run Code Online (Sandbox Code Playgroud)

或者将reset()成员函数添加到BigData:

bigDataPtr->reset(42);
Run Code Online (Sandbox Code Playgroud)

然后它明确你的真实意图是什么,你不需要关心对象的生命周期.


Dre*_*ann 2

是的,通常是安全的。 (致敬马克西姆·叶戈鲁什金(Maxim Yegorushkin)对边缘案例的观察)

请注意下面的拼写错误消息

Boost 将解引用和->运算符定义为

template<class T>
typename boost::detail::sp_dereference< T >::type boost::shared_ptr< T >::operator* () const;

template<class T>
typename boost::detail::sp_member_access< T >::type boost::shared_ptr< T >::operator-> () const;
Run Code Online (Sandbox Code Playgroud)

当这些detail位得到解决后,你就得到了这个

template<class T>
T & boost::shared_ptr< T >::operator* () const

template<class T>
T * boost::shared_ptr< T >::operator-> () const 
Run Code Online (Sandbox Code Playgroud)

所以你直接处理指向的对象。没有代理或其他结构可能会干扰您正在尝试的操作。

就指向的数据而言,您的代码:

bigDataPtr->~BigDataPtr();
new (&*bigDataPtr) BigData;
Run Code Online (Sandbox Code Playgroud)

可能有错别字。但如果你打算:

bigDataPtr->~BigData();
new (&*bigDataPtr) BigData;
Run Code Online (Sandbox Code Playgroud)

它将决心

(BigData pointer)->~BigData();
new (&(BigData reference)) BigData;
Run Code Online (Sandbox Code Playgroud)

这是合法的,并且您是正确的,它可以避免分配时通常产生的额外分配。