• 编程参考 - std::exchange和std::swap的区别


    这两个功能是C++ standard library中的Standard template library中的一部分。容易混淆,我们来看下它们的区别。

    exchange:

    这个函数是一个返回原先值的set函数

    std::exchange is a setter returning the old value. 

    int z = std::exchange(x, y);

    After this line of code executes:

    * x is assigned the value of y,

    * z is assigned the value that x had initially.

    使用伪代码(pseudocode)表示的话,exchange的意思就是:

    z <- x <- y

    x(第一个参数)的值作为返回值赋值给z;y(第二个参数)的值复制给X。

    常用语法定义如下:

    template< class T, class U = T >

    T exchange( T& obj, U&& new_value );

    将第二个参数的值赋给第一个值,并返回第一个参数的旧值。

    #include

    int main()

    {

      int x = 2;

      auto y = std::exchange(x, 4);

      // y == 2;

      // x == 4;

    }

    swap:

    伪代码表示含义:

    A -> B

    B <- A

    交换两个变量的值。

    Semantic and syntax,语义和语法:

    最通常的使用语法如下:

    template< class T >

    void swap( T& a, T& b );

    对模板T类型的要求:

    T must meet the requirements of CopyConstructible and CopyAssignable (until C++11),MoveConstructible and MoveAssignable (since C++11)

    注意swap是不返回值的。这里的参数是对象的引用。

    #include

    int main()

    {

      int i = 3;

      int j = 4;

      std::swap(i, j);

      // i == 4

      // j == 3

    }

    $ g++ -o test std.c -std=c++14

    swap需要他的参数都不是常量引用,要能转换为一个non-const reference,所以不能使用swap(i, 4),编译会不通过。

    使用exchange的场景举例:The “swap-and-iterate” pattern 

    这种模式可以使用exchange来做。在很多event-driven的架构中会使用。一般会有一个vector的事件需要分发(dispatch), 或者等同的意思,需要调用相应的callback。 但我们希望事件处理程序能够产生自己的事件,以便进行延迟分派。(But we want event handlers to be able to produce events of their own for deferred dispatch.)

    代码如下:

    class Dispatcher {

        // We hold some vector of callables that represents

        // events to dispatch or actions to take

        using Callback = /* some callable */;

        std::vector callbacks_;

        // Anyone can register an event to be dispatched later

        void defer_event(const Callback& cb) {

            callbacks_.push_back(cb);

        }

        // All events are dispatched when we call process

        void process() {

            std::vector tmp{};

            using std::swap; // the "std::swap" two-step

            swap(tmp, callbacks_);

            for (const auto& callback : tmp) {

                std::invoke(callback);

            }

        }

    };

    这就是 "swap-and-iterate "模式。这个回调类内部调用 defer_event 并因此产生自己的事件是安全的:我们使用 tmp,这样调用 defer_event 就不会使循环中的迭代器失效。

    但是,我们在这里做的工作比必要的要多一些,而且还犯了 "ITM antipattern(initialize-then-modify)"的错误。首先,我们构造了一个空vector (tmp),然后,通过 swap,我们有 3 个move assignments,然后才开始迭代。

    使用std::exchange进行重构可以解决这些问题:

    class Dispatcher {

        // ...

        // All events are dispatched when we call process

        void process() {

            for (const auto& callback : std::exchange(callbacks_, {}) {

                std::invoke(callback);

            }

        }

    };

    现在,我们不必再声明一个临时量。在 std::exchange 中,我们只有一个移动构造和一个移动赋值,比 swap 节省了一次移动。我们不需要理解 "std::swap 两步法"所涉及的 ADL。我们不需要 tmp,只需要一种表达empty vector的方法,在这里就是 {}。编译器非常善于优化对 std::exchange 的调用,所以我们当然能得到我们通常期望的拷贝消除(copy elision)。因此,代码整体上更加简洁、快速(concise, faster),并提供了与之前相同的安全性。

    从这个角度看exchange就是用来调整一个变量的值来使用的。就像我们一直在用的i++, 后缀操作符,在使用完i的值后,再对i的值进行修改。

    参考:

    1,C++ Weekly: Ask C++ Weekly: `std::exchange` vs `std::swap`

    https://youtu.be/GEbPRS81py4?si=9tvUhpGjKstzCog7

    2,cppreference.com

    std::exchange - cppreference.com

    std::swap - cppreference.com

    3,std::exchange是干什么的

    What std::exchange does, and how to remember it - Fluent C++ (fluentcpp.com)

    4,std::exhange的好处

    std::exchange Patterns: Fast, Safe, Expressive, and Probably Underused - Fluent C++ (fluentcpp.com)

  • 相关阅读:
    使用route的reject拒绝境外ip通信
    Linux操作系统-线程池
    Chain-of-Verification Reduces Hallucination in Lagrge Language Models阅读笔记
    【云原生 | Kubernetes 系列】--Envoy基于gRPC订阅
    openEuler安全配置规范基线
    ELK集群 日志中心集群、kafka、logstash
    Aspose.Words for .NET图表教程——关于使用图表数据
    java字符串(String & StringBuilder)
    随笔 | 写在七月末的这一天
    【Spring连载】使用Spring Data访问 MongoDB----对象映射之对象引用
  • 原文地址:https://blog.csdn.net/guoqx/article/details/132921642