使用 std::move 作为参数传递共享 ptr 的 Boost asio post 警告:高级用例

问题描述

我是 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));

如果两者都正确,哪个更可取?

提前致谢

问候 香卡

解决方法

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<> 使用仅移动处理程序:

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!

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...