我正在尝试在具有队列的线程之间传递按值。
因为有多个不同的对象,所以我做了一个抽象类。
class message
{
public :
virtual ~message(){};
};
然后我有一个子类用于每种不同类型的消息
class a_specific_message : public message
{
...
};
我读了this tutorial来实现队列,我用以下方式调用它:
concurrent_queue<message> queue;
a_specific_message m{1, 2, 3};
queue.push(m);
我的问题是我需要覆盖operator=
,以便队列可以克隆消息
popped_value=the_queue.front();
我尝试添加一个虚拟运算符,但不会在子类中调用它。
我不知道如何在不通过引用传递对象的情况下实现这样的事情。
答案 0 :(得分:2)
正如@PeteBecker在评论中写道,concurrent_queue<message>
按值保存message
。将派生对象实例推入队列时,它仅复制message
部分。发生切片。
使队列保持多种类型的对象而不诉诸指针的一种方法是使用一个有区别的联合,例如: boost::variant
:
using message = boost::variant<specific_message_a, specific_message_b>;
此处不需要消息的通用基类。
这种方法的缺点是sizeof(message)
是sizeof
模板参数列表中最大类型的boost::variant<>
。
答案 1 :(得分:2)
在我看来,多态不是你真正想要的。除了析构函数和动态向下转换之外只有一个接口通常意味着您使用的是错误的工具。
但是,如果你想要多态,那么我建议std::unique_ptr
。你可以在这里找到像这样声明的指针队列:concurrent_queue<std::unique_ptr<message>>
正如你在评论中所说:
我不想使用指针,因为开发人员必须记住在另一个线程中删除它。它可能很容易忘记并且有内存泄漏。
然后我认为std::unqiue_ptr
对你来说是正确的。
如果我翻译你的代码,它会是这样的:
concurrent_queue<std::unique_ptr<message>> queue;
auto m = std::make_unique<a_specific_message>(1, 2, 3);
queue.push(std::move(m));
或者简单地说:
concurrent_queue<std::unique_ptr<message>> queue;
queue.push(std::make_unique<a_specific_message>(1, 2, 3));
// Or
queue.push(new a_specific_message{1, 2, 3});
然后,弹出值:
auto popped_value = std::move(the_queue.front());
然后自动删除所有内容,而不必记住删除任何指针。为此目的创建了std::unique_ptr
。
为了避免代码中的显式移动,您可以在队列中使用pop_value
之类的内容,如下所示:
T pop_value() {
auto value = std::move(the_queue.front());
the_queue.pop();
// use nrvo
return value;
}
现在,在您的主题中,您可以安全地执行此操作:
{
auto some_message = queue.pop_value();
// stuff
} // some_message deleted here.