std::move 在 std::bind 中使该指针无效
std::move disvalidates this pointer in std::bind
我有一个关注串行设备的 class。 (请记住,我发布了重现我观察到的问题的最小示例。实际上有很多错误处理等,为了简单起见我删除了它们 - 因此不要以此来判断我)
class Device
{
public:
void open(const std::string& path) {
fd = ::open(path.c_str(), O_RDWR | O_NOCTTY));
readThread = std::thread(std::bind(&Device::readProc, this));
}
void close() { ::close(fd); }
private:
void readProc() { auto i = read(fd, buffer, sizeof(buffer)); }
std::thread readThread;
int fd;
};
主要是,我将枚举每个设备,如果打开成功,我会将其推入向量中:
for (auto& p : std::filesystem::directory_iterator("/dev/"))
if (p.path().string().substr(0, 11) == "/dev/ttyACM")
{
Device dev;
if (dev.open(p.path().string()))
{
readers.push_back(std::move(dev));
}
else
{
std::cout << "Failed to open device " << p.path() << std::endl;
}
}
问题是,在调用 std::move(dev)
之后,传递给 std::bind
函数的指针似乎失效了。读取 returns -1 并将 errno 设置为 9(无效的描述符)。我调试了它,打开后 fd 的值是 5(随每个程序 运行 变化),而在 readProc() 在std::move
之后变成了-129589(随机值)。
这是正确的行为吗?如果有,如何避免?
编辑: 我已将设备枚举更改为:
readers.emplace_back();
auto& dev = readers.back();
if (!dev.open(p.path().string()))
{
readers.pop_back();
}
这很有效,因此证实了我对 std::move() 的观察,但这远非正确的方法。
此处:
readThread = std::thread(std::bind(&Device::readProc, this));
您将 this
绑定到传递给线程的函数。然后稍后当你打电话时
readers.push_back(std::move(dev));
然后dev
被移动,线程成员也被移动,但是线程仍然有指向被移动的from对象的指针。
在您的固定版本中,情况并非如此,您在容器中已有的 Device
上调用 open
。
Is this the correct behavior?
是的。移动对象 dev
后其 this
仍保持不变。而容器中的对象是不同的this
.
If so, how can it be avoided?
小心传递给线程的引用/指针。一般来说,您需要注意引用/指向的对象仍然存在。
我有一个关注串行设备的 class。 (请记住,我发布了重现我观察到的问题的最小示例。实际上有很多错误处理等,为了简单起见我删除了它们 - 因此不要以此来判断我)
class Device
{
public:
void open(const std::string& path) {
fd = ::open(path.c_str(), O_RDWR | O_NOCTTY));
readThread = std::thread(std::bind(&Device::readProc, this));
}
void close() { ::close(fd); }
private:
void readProc() { auto i = read(fd, buffer, sizeof(buffer)); }
std::thread readThread;
int fd;
};
主要是,我将枚举每个设备,如果打开成功,我会将其推入向量中:
for (auto& p : std::filesystem::directory_iterator("/dev/"))
if (p.path().string().substr(0, 11) == "/dev/ttyACM")
{
Device dev;
if (dev.open(p.path().string()))
{
readers.push_back(std::move(dev));
}
else
{
std::cout << "Failed to open device " << p.path() << std::endl;
}
}
问题是,在调用 std::move(dev)
之后,传递给 std::bind
函数的指针似乎失效了。读取 returns -1 并将 errno 设置为 9(无效的描述符)。我调试了它,打开后 fd 的值是 5(随每个程序 运行 变化),而在 readProc() 在std::move
之后变成了-129589(随机值)。
这是正确的行为吗?如果有,如何避免?
编辑: 我已将设备枚举更改为:
readers.emplace_back();
auto& dev = readers.back();
if (!dev.open(p.path().string()))
{
readers.pop_back();
}
这很有效,因此证实了我对 std::move() 的观察,但这远非正确的方法。
此处:
readThread = std::thread(std::bind(&Device::readProc, this));
您将 this
绑定到传递给线程的函数。然后稍后当你打电话时
readers.push_back(std::move(dev));
然后dev
被移动,线程成员也被移动,但是线程仍然有指向被移动的from对象的指针。
在您的固定版本中,情况并非如此,您在容器中已有的 Device
上调用 open
。
Is this the correct behavior?
是的。移动对象 dev
后其 this
仍保持不变。而容器中的对象是不同的this
.
If so, how can it be avoided?
小心传递给线程的引用/指针。一般来说,您需要注意引用/指向的对象仍然存在。