一对向量构造函数:初始值设定项列表与显式构造

Pair of vector constructors: initializer list vs explicit construction

本文关键字:列表 构造函数 向量      更新时间:2023-10-16

我以两种方式调用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()。我不希望这种行为。有谁知道为什么?我也和叮当核对了一下。

问题来自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),它必须制作一个副本。

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

  • 使用上面提到的第三个构造函数创建自己的pair— 在这种情况下,将选择(3),并移动临时vector;
  • 在构造std::pair时显式构造std::initializer_list<int>
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 );

。但是有一个默认值U,这使得此构造函数成为重载解析的有效候选者。


1当你调用pair{ {1,2,3,4,5}, 1 }时,U1在 [temp.deduct.type]#5.6(2)内处于非推导上下文中,因此演绎失败,这就是选择(1)的原因。