向量构造函数对:初始化列表与显式构造

时间:2018-11-01 20:15:23

标签: c++ c++17 stdvector std-pair

我通过两种方式调用std::pair<vector<int>, int>构造函数:

  • 传递初始化列表
  • 传入显式矢量(r值)。

由于某种原因,初始化器列表版本会进行复制(并销毁一个副本)。
这是我的最小代码示例:

auto dummy() {
    return pair<vector<int>, int>{ {1,2,3,4,5}, 1};
}

auto dummy1() {
    return pair<vector<int>, int>{ vector{1,2,3,4,5}, 1};
}

auto dummy2() {
    return optional<vector<int> > { {1,2,3,4,5} };
}

检查编译器浏览器后,我发现初始化列表dummy()的版本两次调用operator new,一次调用delete。无论是显式构造版本dummy1()还是std::optional中类似的dummy2()构造函数,都不会发生这种情况。我不会期望这种行为。有人知道为什么吗?我也检查了c声。

1 个答案:

答案 0 :(得分:3)

问题来自std::pair构造函数和模板参数推导/重载解析:

pair( const T1& x, const T2& y ); // (1)

template< class U1, class U2 >
pair( U1&& x, U2&& y );           // (2)

请注意,至少有一个“缺失的”构造函数:

pair( T1&& x, T2&& y );           // (3)

当对第一个参数使用列表初始化时,所选的构造函数不是(2)(带有U1 = std::initializer_list<int>),而是(1) 1 。因此,您需要构造一个临时std::vector<int>,它作为对const的{​​{1}}引用的传递,而该副本必须进行复制。

您可以通过以下任一方式凭经验确定这一点:

  • 使用上述第三个构造函数创建自己的(1)-在这种情况下,将选择pair,并移动临时(3)
  • 在构造vector时明确构造std::initializer_list<int>
std::pair

另一方面,pair<vector<int>, int>{ std::initializer_list<int>{1,2,3,4,5}, 1 }; 作为单个模板构造函数:

std::optional

...但是template < class U = value_type > constexpr optional( U&& value ); 有一个默认值,这使此构造函数成为重载解决方案的有效候选对象。


1 调用U时,pair{ {1,2,3,4,5}, 1 }处于U1 [temp.deduct.type]#5.6内的非推论上下文中,因此推论失败,为什么选择(2)