0

我目前对 C++17 保证的 RVO 及其含义感到非常困惑。我知道要启动 NRVO,我需要确保

  1. 通过函数的所有可能返回路径返回一个对象的同一个实例,并且

  2. 在调用端使用函数调用初始化关联对象

考虑一个最简单的装饰类 Widget,我想分配一对没有副本的 Widget,然后返回它

#include<iostream>
#include<utility>

struct Widget {
  Widget() { std::cerr << "Default ctor" << std::endl; }
  explicit Widget(int i) { std::cerr << "custom ctor" << std::endl; }
  Widget(Widget const &) { std::cerr << "copy ctor" << std::endl; }
  Widget(Widget &&) { std::cerr << "move ctor" << std::endl; }
  Widget &operator=(Widget const &) { std::cerr << "copy assign" << std::endl; }
  Widget &operator=(Widget &&) { std::cerr << "move assign" << std::endl; }
  int i_;
};

auto foo(){
  std::pair<Widget,Widget> w;  // default construction
  auto &[w1,w2] = w;
  // do something with w1 and w2
  return w;
}

int main(){
  auto f = foo();
}

没有复制,但现在我尝试使用 make_pair

auto foo(){
  auto w = std::make_pair<Widget,Widget>({},{}); // Awkward syntax and move construction
  auto &[w1,w2] = w;
  // do something with w1 and w2
  return w;
}

如果我想使用 make_pair,这真的是唯一可能的选择吗?与第一个功能相比,为什么要涉及移动构造?

4

1 回答 1

3

我认为你问题的前提是错误的。

如果我想使用 make_pair,这真的是唯一可能的选择吗?

为什么要std::make_pair在这里使用?

auto w = std::make_pair<Widget,Widget>({},{}); // Awkward syntax and move construction

这确实是一种尴尬的语法。让我解释一下我为什么这么认为...

cppreference开始std::make_pair(强调我的):

创建一个 std::pair 对象,从 arguments 的类型推导出目标类型

的唯一目的std::make_pair是推断其参数的类型,例如

std::pair<int,int> x;                         
x = std::pair<int,int>(3,3);     // not nice      
x = std::make_pair(3,3);         // ok

当默认构造一对并且您知道它的类型时,您不必重复模板参数

std::pair<int,int> a = std::pair<int,int>();  // awkward 

当您想要非默认构造时都不要使用(auto当它的唯一影响是您必须在同一行代码中的其他地方拼写类型时不要使用)

std::pair<int,int> a{5,4}; // no move/copy

底线:

std::make_pair另一种方法是在不需要时干脆不使用。

于 2018-10-10T21:04:01.690 回答