You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化代码确保asio::async_send的底层内存块始终有效?

优化方案与改进建议

你的改写已经解决了核心的内存生命周期问题,但还有几个可以优化的点,让代码更安全、简洁且符合Boost.Asio的最佳实践:

1. 优化参数传递,避免意外修改原变量

你当前用std::string&作为参数,内部std::move(str)会清空原字符串,这会给调用者带来意外副作用。更好的做法是传值,利用C++移动语义减少拷贝,同时避免修改外部变量:

void Conversation::do_write(std::string str)  // 改为传值
{
    auto conversation_ptr = shared_from_this();
    std::shared_ptr<std::string> content_ptr = std::make_shared<std::string>(std::move(str));
    m_socket.async_send(asio::buffer(*content_ptr), 
        [this, conversation_ptr, content_ptr](std::error_code error, size_t length) {
            if (!error) {
                std::cout << "数据写入成功,字节数:" << length << std::endl;
            } else {
                std::cout << "写入数据出错:" << error.message() << std::endl;
            }
        });
}

调用者传左值时会触发一次拷贝,传右值时直接移动,语义清晰且不会意外修改原变量。

2. 解决异步写的并发问题(关键优化)

Boost.Asio的流套接字不允许同时发起多个异步写操作,多次调用原do_write会导致未定义行为。需维护写队列保证操作串行执行:

首先在Conversation类中添加成员变量:

std::queue<std::shared_ptr<std::string>> m_write_queue;

然后修改do_write并新增执行写操作的函数:

void Conversation::do_write(std::string str)
{
    auto content_ptr = std::make_shared<std::string>(std::move(str));
    bool was_empty = m_write_queue.empty();
    m_write_queue.push(content_ptr);
    
    if (was_empty) {
        do_write_impl();
    }
}

void Conversation::do_write_impl()
{
    auto conversation_ptr = shared_from_this();
    auto content_ptr = m_write_queue.front();
    m_socket.async_send(asio::buffer(*content_ptr),
        [this, conversation_ptr, content_ptr](std::error_code error, size_t length) {
            m_write_queue.pop();
            
            if (!error) {
                std::cout << "数据写入成功,字节数:" << length << std::endl;
            } else {
                std::cout << "写入数据出错:" << error.message() << std::endl;
                // 可在此处理连接断开等错误,比如关闭套接字
            }
            
            // 队列非空则继续执行下一次写操作
            if (!m_write_queue.empty()) {
                do_write_impl();
            }
        });
}

所有写请求会排队执行,只有当前写操作完成后才会启动下一个,完全符合Boost.Asio的规范。

3. 简化捕获,避免冗余

lambda中this和conversation_ptr作用重复(均保证Conversation对象存活),可直接捕获shared_from_this(),无需同时捕获this:

// 在do_write_impl中
m_socket.async_send(asio::buffer(*content_ptr),
    [conversation_ptr, content_ptr](std::error_code error, size_t length) {
        conversation_ptr->m_write_queue.pop();
        
        if (!error) {
            std::cout << "数据写入成功,字节数:" << length << std::endl;
        } else {
            std::cout << "写入数据出错:" << error.message() << std::endl;
        }
        
        if (!conversation_ptr->m_write_queue.empty()) {
            conversation_ptr->do_write_impl();
        }
    });

避免捕获this带来的悬空风险,语义更清晰。

4. 可选:利用Boost.Asio动态缓冲区

不想手动管理shared_ptr的话,可使用asio::dynamic_buffer配合队列,底层内存由队列保证有效性:

// 成员变量改为存储string的队列
std::queue<std::string> m_write_queue;

void Conversation::do_write(std::string str)
{
    bool was_empty = m_write_queue.empty();
    m_write_queue.push(std::move(str));
    
    if (was_empty) {
        do_write_impl();
    }
}

void Conversation::do_write_impl()
{
    auto conversation_ptr = shared_from_this();
    auto& content = m_write_queue.front();
    m_socket.async_send(asio::dynamic_buffer(content),
        [this, conversation_ptr](std::error_code error, size_t length) {
            m_write_queue.pop();
            
            if (!error) {
                std::cout << "数据写入成功,字节数:" << length << std::endl;
            } else {
                std::cout << "写入数据出错:" << error.message() << std::endl;
            }
            
            if (!m_write_queue.empty()) {
                do_write_impl();
            }
        });
}

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:15:19