gpt4 book ai didi

C++11 std::thread 和虚函数绑定(bind)

转载 作者:可可西里 更新时间:2023-11-01 16:42:14 24 4
gpt4 key购买 nike

我遇到了奇怪的 C++ 代码行为,不确定这是编译器错误还是我的代码的未定义/未指定行为。这是代码:

#include <unistd.h>
#include <iostream>
#include <thread>

struct Parent {
std::thread t;

static void entry(Parent* p) {
p->init();
p->fini();
}

virtual ~Parent() { t.join(); }

void start() { t = std::thread{entry, this}; }

virtual void init() { std::cout << "Parent::init()" << std::endl; }
virtual void fini() { std::cout << "Parent::fini()" << std::endl; }
};

struct Child : public Parent {
virtual void init() override { std::cout << "Child::init()" << std::endl; }
virtual void fini() override { std::cout << "Child::fini()" << std::endl; }
};

int main() {
Child c;

c.start();
sleep(1); // <========== here is it

return 0;
}

代码的输出如下,这并不奇怪:

Child::init()
Child::fini()

但是,如果函数调用“sleep(1)”被注释掉,输出将是:

Parent::init()
Parent::~fini()

在 Ubuntu 15.04 上测试,gcc-4.9.2 和 clang-3.6.0 表现出相同的行为。编译器选项:

g++/clang++ test.cpp -std=c++11 -pthread

它看起来像一个竞争条件(在线程启动之前 vtable 没有完全构建)。这段代码格式错误吗?编译器错误?或者它应该是这样的?

最佳答案

@KerrekSB commented:

The thread uses the child object, but the child object is destroyed before the thread is joined (because the joining only happens after the destruction of the child has begun).

Child 对象在 main 结束时被销毁。 Child 析构函数被执行,并有效地调用了 Parent 析构函数,其中 Parent 基(没有这样)和数据成员(线程对象)是被毁。随着析构函数在基类链中向上调用,对象的动态类型发生变化,其顺序与构造期间的变化顺序相反,因此此时对象的类型为Parent.

线程函数中的虚拟调用可以发生在 Child 析构函数调用之前、重叠或之后,在重叠的情况下,有一个线程访问存储(实际上,vtable 指针) 正在被另一个线程更改。所以这是未定义的行为。

关于C++11 std::thread 和虚函数绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33172001/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com