gpt4 book ai didi

c++ - C++中类成员函数相互调用有什么好处?

转载 作者:搜寻专家 更新时间:2023-10-31 02:11:16 25 4
gpt4 key购买 nike

我是 C++ 新手。我发现下面的编程风格对我来说很有趣。我在这里写了一个简化版本。

#include <iostream>
using namespace std;
class MyClass {
public :
MyClass(int id_) : id(id_) {
cout<<"I am a constructor"<<endl;
}
bool error = false;
void run() {
//do something ...
if (!error) {
read();
}
}
void read() {
//do something ...
if (!error) {
write();
}
}
void write() {
//do something ...
if (!error) {
read();
}
}
private :
int id;
};
int main() {
MyClass mc(1);
mc.run();
return 0;
}

这里的示例是可编译的,但我没有运行它,因为我必须进入无限循环。但是,我希望以此作为引用。 read() 和 write() 互相调用。我第一次遇到这种编程风格是在 boost.asio .当服务器在 do_read() 中收到一条消息时,它调用 do_write() 来回应客户端,然后在 do_write() 结束时再次调用 do_read() 。

关于这种类型的编码,我有两个问题。

  1. 会不会导致栈溢出?因为函数一直在调用自己,函数结束时只会发生错误。

  2. 它有什么优势?为什么我不能使用函数按顺序循环它们并在遇到错误时中断循环。

    bool replied = true;

    while (!error) {

    if (replied) read();

    else {

    write();

    replied = !replied;

    }

    }

最佳答案

您的简化版本遗漏了最重要的方面:write()read() 调用是异步

因此,这些函数实际上不会导致递归,请参阅最近的回答:Do "C++ boost::asio Recursive timer callback" accumulate callstack?

async_read(...)async_write(...) 的“不同寻常”之处在于,函数在 IO 操作实际执行之前返回,更别说完成了。实际执行是按不同的时间表完成的。

为了将完成信号返回给“调用者”,异步调用通常采用完成处理程序,它会根据 IO 操作的结果进行调用。

在该完成处理程序中,通常会看到通信 channel 的结束或正在安排的下一个 IO 操作。这被称为异步调用链,在许多支持异步操作的语言中都非常突出²

这需要一些时间来适应,但最终您会习惯这种模式。

考虑到这一点,重新审视其中一个 boost 示例,看看一分钱是否下降:

Documentation sample Chat Client

  void handle_connect(const boost::system::error_code& error)
{
if (!error)
{
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
boost::bind(&chat_client::handle_read_header, this,
boost::asio::placeholders::error));
}
}

void handle_read_header(const boost::system::error_code& error)
{
if (!error && read_msg_.decode_header())
{
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
boost::bind(&chat_client::handle_read_body, this,
boost::asio::placeholders::error));
}
else
{
do_close();
}
}

void handle_read_body(const boost::system::error_code& error)
{
if (!error)
{
std::cout.write(read_msg_.body(), read_msg_.body_length());
std::cout << "\n";
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
boost::bind(&chat_client::handle_read_header, this,
boost::asio::placeholders::error));
}
else
{
do_close();
}
}

void do_write(chat_message msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
boost::bind(&chat_client::handle_write, this,
boost::asio::placeholders::error));
}
}

void handle_write(const boost::system::error_code& error)
{
if (!error)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
boost::bind(&chat_client::handle_write, this,
boost::asio::placeholders::error));
}
}
else
{
do_close();
}
}

void do_close()
{
socket_.close();
}

异步操作的好处

异步 ​​IO 对于更基于事件的 IO 模型很有用。当扩展到大量 IO 操作时,它们还消除了第一个“天花板”。在传统的命令式代码模式中,许多客户端/连接需要许多线程才能同时为它们提供服务。但在实践中,线程无法扩展(因为典型服务器的逻辑 CPU 数量很少),这意味着 IO 操作会相互阻塞³。

使用异步 IO,您通常可以在单个线程上执行所有 IO 操作,从而大大 boost 效率 - 从而 boost 程序设计的某些方面(因为需要涉及的线程问题更少)。


¹ 存在许多选择,但假设 io_service::run() 在单独的线程上运行,这将导致 IO 操作实际执行,可能在需要时恢复并在该线程上完成线程

² 我想说 javascript 因这种模式而声名狼藉

³ 一个典型的例子是远程过程调用在等待时保持线程被占用。要完成的数据库查询

关于c++ - C++中类成员函数相互调用有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43884931/

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