由于移动构造函数而删除了对象

时间:2013-03-27 14:51:00

标签: c++ multithreading c++11 move-constructor

我正在尝试创建一个在专用线程中运行的函数 从串口读取。但是我无法通过连接 到线程。我将代码缩减为以下示例:

#include <thread>
#include <boost/asio.hpp>

template <typename Port>
void serial_read( Port& port) {}

int main()
{
  boost::asio::io_service serial_io;
  boost::asio::serial_port port( serial_io );
  port.open( "/dev/ttyUSB0" );

  std::thread s( serial_read<boost::asio::serial_port>, port );
  return 0;
}

但是,我收到以下错误消息:

/usr/include/c++/4.7/tuple:128:25: error: use of deleted function ‘boost::asio::basic_serial_port<>::basic_serial_port(const boost::asio::basic_serial_port<>&)’
In file included from /usr/include/boost/asio.hpp:25:0,
                 from main.cpp:2:
/usr/include/boost/asio/basic_serial_port.hpp:47:7: note: ‘boost::asio::basic_serial_port<>::basic_serial_port(const boost::asio::basic_serial_port<>&)’ is implicitly declared as deleted because ‘boost::asio::basic_serial_port<>’ declares a move constructor or move assignment operator

错误信息非常清楚。我正在尝试使用一个对象 这是不存在的,因为它已被删除 移动构造函数的声明。但我还是不明白 这里发生了什么,以及如何正确地做到这一点。有人可以 赐教?

2 个答案:

答案 0 :(得分:3)

您没有正确阅读错误。它告诉您boost::asio::basic_serial_port复制构造函数delete d。这意味着无法使用复制构造函数。它与被删除的对象无关。复制构造函数为delete d的原因是因为定义了移动构造函数。

如果您确实需要传递对serial_read的引用,则需要将port对象包装在reference_wrapper中:

std::thread s( serial_read<boost::asio::serial_port>, std::ref(port) );

但是,如果您不保留port并将其用于其他任何事情(例如将相同的port对象传递给其他线程),则应std::move你的port对象进入主题:

std::thread s( serial_read<boost::asio::serial_port>, std::move(port) );

这还需要将serial_read的定义更改为按值Port

template <typename Port>
void serial_read( Port port) {}

答案 1 :(得分:2)

简单修复(我相信,未经测试)是使用引用包装器(如果你真的需要在main和线程中维护对象):

std::thread s(&serial_read<boost::asio::serial_port>,std::ref(port));

问题在于std::thread(因为std::bind将创建一个带有参数副本的仿函数),以后会被使用(没有参数)。基本上上面的调用类似于:

std::thread( std::bind(&serial_read<boost::asio::serial_port>,std::ref(port)) );

bound 对象中,存储每个参数的副本,这要求参数可以复制构造。使用引用包装器允许复制(复制包装器,原始对象不复制)。

另一种替代方法是,如果您不需要在port中保持main对象有效,则可以从中移除,以便复制而不是 >绑定对象,允许实现从main中的对象移动