std :: pair中的初始化列表


26

这段代码:

#include <iostream>
#include <string>

std::pair<std::initializer_list<std::string>, int> groups{ { "A", "B" }, 0 };

int main()
{
    for (const auto& i : groups.first)
    {
        std::cout << i << '\n';
    }
    return 0;
}

编译但返回段错误。为什么?

在gcc 8.3.0和在线编译器上进行了测试。


1
为方便起见:带有 带有的 Godbolt链接std::pair
Max Langhof

Answers:


24

std::initializer_list并不意味着要存储,而只是为了...好初始化。在内部,它仅存储指向第一个元素和大小的指针。在您的代码中,这些std::string对象是临时对象initializer_list,它们都不拥有它们的所有权,也没有延长其寿命,也没有复制它们(因为它不是容器),因此它们在创建后立即超出范围,但是您initializer_list仍然拥有指向它们的指针。这就是为什么您会遇到细分错误。

要存储,应使用std::vector或之类的容器std::array


使我感到困扰的是这是可编译的。愚蠢的语言:(
轨道上的亮度竞赛

1
@LightnessRaceswithMonica我吃了很多牛肉initializer_list。不能使用仅移动对象,因此,例如,不能将list init与unique_ptr的向量一起使用。的大小initializer_list不是编译时常量。与事实std::vector<int>(3)std::vector<int>{3}做完全不同的事情。让我难过:(
bolov

是的,同样... :(
轨道上的亮度竞赛

3

我只想添加更多细节。底层的std::initializer_list行为类似于临时对象。考虑以下类别:

struct X
{
   X(int i) { std::cerr << "ctor\n"; }
   ~X() { std::cerr << "dtor\n"; }
};

及其在以下代码中的用法:

std::pair<const X&, int> p(1, 2);
std::cerr << "barrier\n";

打印出来

ctor
dtor
barrier

因为在第一行,是类型的临时实例 X创建(通过将构造函数从转换1),并且也将其销毁。然后将存储的参考p悬空。

至于 std::initializer_list,如果您以这种方式使用它:

{
   std::initializer_list<X> l { 1, 2 };
   std::cerr << "barrier\n";
}

那么,底层(临时)数组只要存在 l。因此,输出为:

ctor
ctor
barrier
dtor
dtor

但是,如果您切换到

std::pair<std::initializer_list<X>, int> l { {1}, 2 };
std::cerr << "barrier\n";

输出再次

ctor
dtor
barrier

因为基础(临时)数组仅存在于第一行。取消引用指向元素的指针会l导致未定义的行为。

现场演示在这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.