博客

  • Cpp 专题

    RVO / NRVO

    Return value optimzation 和 Named Return value optimzation

    T make() {
      return T{}; // RVO
    }
    T make() {
      T a{};
      return a; // NRVO
    }
    T make(bool v) {
      T a{};
      T b{};
      if (v) {
        return a; // NRVO 通常做不了,可能退化为move constrcution
      }
      return b; // std::move
    }

    简单来说就是编译器会自动帮助我们做返回值优化,目标对象直接在最终位置构造,中间对象根本不产生,所以 copy/move constructor 都不会被调用。无论是在返回上构造还是返回一个已构造的值,不用去写以下类似的代码,当NRVO优化不了的时候,也会优先尝试move constructor,其实是 copy constructor。

    return std::move(x);

    std::move

    std::move本质上是将一个value转化为右值引用,配合语境后才会具体调用move constructor / move assignment。

    auto b = std::move(a); // move constructor
    T c{};
    c = std::move(b); // move assignment

    std::move 在 std::array 和 std::vector 上的区别

    std::array 的本质是一个数组,所以当对std::array做移动构造的时候,会逐个移动里面的元素,而std::vector结构本质是在管理指针,所以当移动构造的时候,会直接移交指针的控制权。

    std::array<int, 10> a;
    auto b = std::move(b); // 复制 10 个int
    std::vector<int> a(10, 0);
    auto b = std::move(a); // 复制三个指针

    但是如果是std::array<std::string, N> 情况又会不一样,因为int本身是最基础的数据结构,所以移动构造和拷贝构造基本一样,但是如果类型是std::string的时候,std::array移动构造会直接调用元素的移动构造函数,虽然这个时候也是O(n)复杂度,但是移动构造和拷贝构造会有区别。

    std::array<std::string, 10> a;
    auto b = std::move(a); // 移交10个string的buffer
    auto c = a; // 复制10个buffer


    noexcept

    声明一个函数是否是异常安全的,一个具体的例子是,当std::vector<T>扩容的时候,因为扩容的时候会考虑到异常安全,如果T的移动构造函数声明了 noexcept,这个时候会调用移动构造函数,当移动构造函数不是noexcept的时候,扩容的时候会考虑使用拷贝构造函数。

    constexpr / consteval

    一句话:

    • constexpr funciton: 编译和运行期都能用
    • consteval function: 只有编译能用
    • constexpr value: 必须编译期完成初始化,const类型
    • constinit value: 必须编译期完成初始化,不一定是cosnt类型

  • 世界,您好!

    欢迎使用 WordPress。这是您的第一篇文章。编辑或删除它,然后开始写作吧!