【问题标题】:Boost asio post with shared ptr passed as argument with std::move使用 std::move 作为参数传递的共享 ptr 提升 asio 帖子
【发布时间】:2021-07-15 07:03:48
【问题描述】:

我是 boost:asio 的新手。我需要将 shared_ptr 作为参数传递给处理函数。

例如

  1. boost::asio::post(std::bind(&::function_x, std::move(some_shared_ptr)));

使用 std::move(some_shared_ptr) 正确吗?还是我应该如下使用,

  1. boost::asio::post(std::bind(&::function_x, some_shared_ptr));

如果两者都是正确的,哪一个是可取的?

提前致谢

问候 尚卡尔

【问题讨论】:

    标签: boost std bind shared-ptr stdmove


    【解决方案1】:

    Bind 按值存储参数。

    所以两者都是正确的并且可能是等价的。如果在绑定之后不使用some_argument,则将参数移动到绑定中可能会更有效。

    警告:高级用例

    (如果你想跳过这个

    不是你问的那样:如果 function_x 采用右值引用参数会怎样?

    很高兴你问。你不能。但是,您仍然可以通过左值引用接收并从中移动。因为:

    std::move doesn't move

    右值引用仅用于指示可能从参数中移出的参数,以启用一些智能编译器优化和诊断。

    所以,只要您知道您的绑定函数只执行一次(!!),那么从左值参数移动是安全的。

    在共享指针的情况下,实际上还有一点余地,因为从共享指针移动实际上根本不会移动指向的元素。

    所以,一个小练习来证明这一切:

    Live On Coliru

    #include <boost/asio.hpp>
    #include <memory>
    #include <iostream>
    
    static void foo(std::shared_ptr<int>& move_me) {
        if (!move_me) {
            std::cout << "already moved!\n";
        } else {
            std::cout << "argument: " << *std::move(move_me) << "\n";
            move_me.reset();
        }
    }
    
    int main() {
    
        std::shared_ptr<int> arg      = std::make_shared<int>(42);
        std::weak_ptr<int>   observer = std::weak_ptr(arg);
    
        assert(observer.use_count() == 1);
    
        auto f = std::bind(foo, std::move(arg));
    
        assert(!arg);                      // moved
        assert(observer.use_count() == 1); // so still 1 usage
    
        {
            boost::asio::io_context ctx;
            post(ctx, f);
            ctx.run();
        }
    
        assert(observer.use_count() == 1); // so still 1 usage
        f(); // still has the shared arg
    
         // but now the last copy was moved from, so it's gone
        assert(observer.use_count() == 0); //
        f(); // already moved!
    }
    

    打印

    argument: 42
    argument: 42
    already moved!
    

    为什么要打扰?

    您为什么要关心以上内容?好吧,因为在 Asio 中有很多处理程序可以保证精确执行一次,所以有时可以避免共享指针的开销(同步、控制块的分配、删除器的类型擦除)。

    也就是说,您可以使用 std::unique_ptr&lt;&gt; 来使用仅移动处理程序:

    Live On Coliru

    #include <boost/asio.hpp>
    #include <memory>
    #include <iostream>
    
    static void foo(std::unique_ptr<int>& move_me) {
        if (!move_me) {
            std::cout << "already moved!\n";
        } else {
            std::cout << "argument: " << *std::move(move_me) << "\n";
            move_me.reset();
        }
    }
    
    int main() {
        auto arg = std::make_unique<int>(42);
        auto f = std::bind(foo, std::move(arg)); // this handler is now move-only
    
        assert(!arg); // moved
    
        {
            boost::asio::io_context ctx;
            post(
                ctx,
                std::move(f)); // move-only, so move the entire bind (including arg)
            ctx.run();
        }
    
        f(); // already executed
    }
    

    打印

    argument: 42
    already moved!
    

    这将在使用大量组合操作的代码中大有帮助:您现在可以零开销将操作的状态绑定到处理程序中,即使它更大且动态分配.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多