C++ 在线程之间按值传递对象

C++ 在线程之间按值传递对象,c++,c++11,C++,C++11,我正试图通过值在具有队列的线程之间传递对象 因为有多个不同的对象,所以我创建了一个抽象类 class message { public : virtual ~message(){}; }; 然后我为每种不同类型的消息创建了一个子类 class a_specific_message : public message { ... }; 我阅读了有关实现队列的内容,并按以下方式对其进行了调用: concurrent_queue<message> queue; a_spec

我正试图通过值在具有队列的线程之间传递对象

因为有多个不同的对象,所以我创建了一个抽象类

class message
{
public :
      virtual ~message(){};
}; 
然后我为每种不同类型的消息创建了一个子类

class a_specific_message : public message
{
...
};
我阅读了有关实现队列的内容,并按以下方式对其进行了调用:

concurrent_queue<message> queue;
a_specific_message m{1, 2, 3};
queue.push(m);
我试图添加一个虚拟操作符,但在子类中没有调用它


我不知道如果不通过引用传递对象,我怎么能实现这样的事情

正如@PeteBecker在评论中所写,
并发队列
按值保存
消息
。当派生对象实例被推入队列时,它只复制
消息
部分。切片发生

使队列保留多种类型的对象而不诉诸指针的一种方法是使用有区别的并集,例如:

使用message=boost::variant;
此处不需要消息的公共基类


这种方法的缺点是
sizeof(message)
boost::variant
模板参数列表中最大类型的
sizeof

正如@PeteBecker在评论中所写,
并发队列
按值保存
消息
。当派生对象实例被推入队列时,它只复制
消息
部分。切片发生

使队列保留多种类型的对象而不诉诸指针的一种方法是使用有区别的并集,例如:

使用message=boost::variant;
此处不需要消息的公共基类


这种方法的缺点是
sizeof(message)
boost::variant
模板参数列表中最大类型的
sizeof

在我看来,多态性并不是你真正想要的。只有析构函数和动态向下转换的接口通常意味着您使用了错误的工具


然而,如果多态性是您想要的,那么让我建议
std::unique\u ptr
。您可以在这里声明指针队列:
concurrent\u queue

正如你在评论中所说:

我不想使用指针,因为开发者必须记住在另一个线程中删除它。它可能很容易忘记,并有内存泄漏

那么我认为
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));
T pop_value() {
    auto value = std::move(the_queue.front());

    the_queue.pop();

    // use nrvo
    return value;
}
然后,所有内容都会自动删除,无需记住删除任何指针<代码>std::unique_ptr已为此目的创建

为了避免代码中的显式移动,您可以在队列中设置类似于
pop_value
的内容,实现方式如下:

concurrent_queue<std::unique_ptr<message>> queue;
auto m = std::make_unique<a_specific_message>(1, 2, 3);

queue.push(std::move(m));
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.

在我看来,多态性并不是你真正想要的。只有析构函数和动态向下转换的接口通常意味着您使用了错误的工具


然而,如果多态性是您想要的,那么让我建议
std::unique\u ptr
。您可以在这里声明指针队列:
concurrent\u queue

正如你在评论中所说:

我不想使用指针,因为开发者必须记住在另一个线程中删除它。它可能很容易忘记,并有内存泄漏

那么我认为
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));
T pop_value() {
    auto value = std::move(the_queue.front());

    the_queue.pop();

    // use nrvo
    return value;
}
然后,所有内容都会自动删除,无需记住删除任何指针<代码>std::unique_ptr已为此目的创建

为了避免代码中的显式移动,您可以在队列中设置类似于
pop_value
的内容,实现方式如下:

concurrent_queue<std::unique_ptr<message>> queue;
auto m = std::make_unique<a_specific_message>(1, 2, 3);

queue.push(std::move(m));
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.


concurrent_queue
保存类型为
message
的对象。当您将派生类型的对象推送到队列中时,该对象将被切片,存储的只是消息的
部分。一旦发生这种情况,就没有办法找回原始对象。您需要一个包含引用或指针的队列。@PeteBecker我担心会发生这种情况。如何确保另一个线程在完成时删除该对象?听起来像是
共享\u ptr
(线程安全)@Marc create virtual的任务destructor@W.F.还是会被切成片。需要指针或引用。
concurrent\u queue
保存类型为
message
的对象。当您将派生类型的对象推送到队列中时,该对象将被切片,存储的只是消息的
部分。一旦发生这种情况,就没有办法找回原始对象。您需要一个包含引用或指针的队列。@PeteBecker我担心会发生这种情况。如何确保另一个线程在完成时删除该对象?听起来像是
共享\u ptr
(线程安全)@Marc create virtual的任务destructor@W.F.还是会被切成片。需要指针或引用。make_是唯一的c++14吗?我收到一个错误,说它不是std的成员,我正在使用c++11是的,
std::make_unique
是c++14的一部分。但是,您可以将
std::make_unique
替换为普通的旧
new
@Marc查看我的编辑。我添加了一个与new兼容的示例,该示例与
std::unique\u ptr
兼容,谢谢,但您确定这会起作用吗?您推送的是特定的消息,而不是唯一的消息。我得到了一个错误:std::unique_ptr(新的特定于_的_消息(1,2,3));make_是唯一的c++14吗?我收到一个错误,说它不是std的成员,我正在使用c++11是的,
std::make_unique
是c++14的一部分。但是,您可以将
std::make_unique
替换为普通的旧
new
@Marc查看我的编辑。我添加了一个与new兼容的示例,它与
std::