std::pair 中的初始化程序列表
Initializer list inside std::pair
此代码:
#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;
}
编译但 returns 段错误。为什么?
已在 gcc 8.3.0 和在线编译器上测试。
std::initializer_list
不是用来存储的,它只是用于...以及初始化。在内部它只存储指向第一个元素和大小的指针。在您的代码中, std::string
对象是临时对象, initializer_list
既不拥有它们,也不延长它们的寿命,也不复制它们(因为它不是容器),因此它们在创建后立即超出范围,但是您的 initializer_list
仍然持有指向它们的指针。这就是您出现分段错误的原因。
对于存储,您应该使用容器,例如 std::vector
或 std::array
。
我想补充一点细节。 std::initializer_list
的底层数组的行为类似于临时数组。考虑以下 class:
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
元素的指针会导致未定义的行为。
现场演示是 here。
此代码:
#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;
}
编译但 returns 段错误。为什么?
已在 gcc 8.3.0 和在线编译器上测试。
std::initializer_list
不是用来存储的,它只是用于...以及初始化。在内部它只存储指向第一个元素和大小的指针。在您的代码中, std::string
对象是临时对象, initializer_list
既不拥有它们,也不延长它们的寿命,也不复制它们(因为它不是容器),因此它们在创建后立即超出范围,但是您的 initializer_list
仍然持有指向它们的指针。这就是您出现分段错误的原因。
对于存储,您应该使用容器,例如 std::vector
或 std::array
。
我想补充一点细节。 std::initializer_list
的底层数组的行为类似于临时数组。考虑以下 class:
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
元素的指针会导致未定义的行为。
现场演示是 here。