我有一些管理 unique_ptrs 队列的代码。在其主循环中,它从队列中弹出一个条目,对其执行某些操作,然后允许该元素超出范围并被删除。到目前为止,没有问题。
我想添加一个功能,我们可以将其移动到其他地方,而不是必须删除该元素。问题是只有元素本身知道是否执行此操作或需要去哪里。
主循环类似于:
std::deque< std::unique_ptr<Object> > queue;
while( !queue.empty() ) {
auto element = std::move( queue.front() );
queue.pop_front();
element->do_something();
element->recycle( std::move(element) ); // ?
}
如果回收不是对象的方法,这将不是问题,但因为它是对象的方法,我不确定它应该是什么样子。通过上面的代码,我会得到类似的东西:
class Object {
public:
virtual void do_something();
virtual void recycle( std::unique_ptr<Object> unique_this ) {
// move unique_this somewhere, or don't and allow it to be deleted
}
};
这样安全吗?如果recycle不移动unique_this,它将在它自己的方法之一中删除它(不过在方法的末尾)。有问题吗?
我想到避免删除这一点的一种可能性是让回收利用左值引用获取 unique_ptr,我意识到这有点奇怪。这个想法是,如果它愿意,它会将其移动到某个地方,但如果不这样做,则直到回收返回后该对象才会被删除。不过,它不一定避免在其方法之一中可能删除对象的问题,因为我们必须确保将其移动到的任何位置都不会立即删除它。
如果这样做不安全,后备计划是让 Object 返回一个回收器(即,一个不是执行回收的 Object 方法的可调用对象)。我认为这应该是可能的,但是考虑到不同的对象想要使用不同的回收器,管理回收器的类型和生命周期会有点混乱。
在我看来,第一个想法(按值传递 unqiue_ptr)是最好的,除非它违反任何规则。这样安全吗?有更好的方法吗?
这样安全吗?
是的。
如果recycle不移动unique_this,它将在它自己的方法之一中删除this(不过在方法的末尾)。有问题吗?
没有。
对象甚至可以在其自己的成员函数中
delete this;
。
element->recycle(std::move(element));
在C++17之前是有问题的:
element->
可能会在移动构造函数之后求值,因此是 nullptr
。太不安全了。
自 C++17 起,求值顺序 (13) 指定在求值参数之前先求值
element->
;所以很安全。