gpt4 book ai didi

C++ lambda函数调用纯虚函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:50:14 30 4
gpt4 key购买 nike

我正在尝试为 std::thread 创建一个包装器类。此类提供了一个启动线程并调用纯虚函数的 kick 方法。我正在使用派生类来调用这个 kick 方法,派生类也实现了虚函数。

class Executor
{
public:
// constructor
Executor();

// destructor
~Executor();

// kick thread execution
void Kick();

private:
// thread execution function
virtual void StartExecution() = 0;

// thread handle
std::thread mThreadHandle;
};

下面是执行器类的实现

Executor::Executor()
{
// Nothing to be done here
}

Executor::~Executor()
{
if (mThreadHandle.joinable())
mThreadHandle.join();
}

void Executor::Kick()
{
// mThreadHandle = std::thread(&Executor::StartExecution, this);
mThreadHandle = std::thread([this] {this->StartExecution();});
}

我正在使用继承此类并实现 StartExecution 方法的 Consumer 类。当我使用 kick 方法时,它显示调用了纯虚函数并且程序终止。

std::unique_ptr<Consumer> consumer = std::make_unique<Consumer>();
consumer->Kick();

在executor kick方法中。我添加了一个断点并开始寻找问题所在。到了

mThreadHandle = std::thread([this] {this->StartExecution();});

行两次。首先是因为 kick 方法,其次是执行 lambda 函数。第一次看到this指向Consumer类。但是当涉及到 lambda 函数时,它就搞砸了,vptr 指向纯虚函数。

我会对其中的错误感兴趣,而不是简单的回答

最佳答案

只是基于我所尝试的猜测:您的 Consumer 在线程执行之前被破坏。

我已将 ~Executor 虚拟化并为相关函数调用添加了一些打印语句。

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>

class Executor
{
public:
// constructor
Executor();

// destructor
virtual ~Executor();

// kick thread execution
void Kick();

private:
// thread execution function
virtual void StartExecution() { std::cout << "Executor::Kick\n"; }

// thread handle
std::thread mThreadHandle;
};

Executor::Executor()
{
// Nothing to be done here
}

Executor::~Executor()
{
std::cout << "~Executor\n";
if (mThreadHandle.joinable())
mThreadHandle.join();
}

void Executor::Kick()
{
// mThreadHandle = std::thread(&Executor::StartExecution, this);
mThreadHandle = std::thread([this] {this->StartExecution();});
}


class Consumer: public Executor {
public:
~Consumer() {
std::cout << "~Consumer\n";
}
private:
virtual void StartExecution() { std::cout << "Consumer::Kick\n"; }
};

int main() {
{
std::cout << "1:\n";
std::unique_ptr<Consumer> consumer = std::make_unique<Consumer>();
consumer->Kick();
}
{
std::cout << "2:\n";
std::unique_ptr<Consumer> consumer = std::make_unique<Consumer>();
consumer->Kick();
std::cout << "Sleeping for a bit\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}

输出:

1:
~Consumer
~Executor
Executor::Kick
2:
Sleeping for a bit
Consumer::Kick
~Consumer
~Executor

See it run here

在销毁消费者之前休眠让线程运行并调用正确的函数。一个“真正的”解决方案是确保消费者至少与线程本身一样长。由于线程存在于基类 Executor 中,因此不能保证这一点,因为派生类在基类之前被破坏。

来自 cppreference (强调我的):

When a virtual function is called directly or indirectly from a constructor or from a destructor (including during the construction or destruction of the class’s non-static data members, e.g. in a member initializer list), and the object to which the call applies is the object under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. In other words, during construction or destruction, the more-derived classes do not exist.

这似乎适用于在构造/析构期间在不同线程中调用成员函数的情况。

关于C++ lambda函数调用纯虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50658692/

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