在 clang 中返回 std::initializer_list
Returning std::initializer_list in clang
考虑这个代码示例:
#include <initializer_list>
#include <iostream>
int main()
{
for(auto e: []()->std::initializer_list<int>{return{1,2,3};}())
std::cout<<e<<std::endl;
return 0;
}
我尝试用g++编译它(gcc版本4.9.2(Debian 4.9.2-10))
并且输出是正确的。
在 clang++ (Debian clang version 3.5.0-9 (tags/RELEASE_350/final) (based on LLVM 3.5.0)) 中输出例如:
0
2125673120
32546
其中第一行始终为 0,最后两行为 "random".
是clang的错误还是别的什么?我认为这个代码示例是正确的。
更新:
当 lambda 函数 return 类型为其他类型(例如 std::vector 或 std::array)时,此代码工作正常。
在 C++11 中,不保证底层数组在原始初始化列表对象的生命周期结束后仍然存在。因此,您的代码可能会出现未定义的行为。切换到 C++14。
来自 C++11 8.5.4 列表初始化 [dcl.init.list]:
5 An object of type std::initializer_list<E>
is constructed from an initializer list as if the implementation allocated an array of N
elements of type E
, where N
is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list<E>
object is constructed to refer to that array. If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.
6 The lifetime of the array is the same as that of the initializer_list
object.
你的 lambda 的 return
语句初始化了一个临时的 std::initializer_list<int>
和 returns 的副本。这一切都很好,除了它所引用的数组的生命周期在完整表达式的末尾结束。通过 lambda 外部的 initializer_list
访问死数组会导致未定义的行为。
initializer_list
不是容器,它是对临时容器的引用。如果你想把它当作一个容器来使用,你会很不愉快。
在 C++14(引用 N4140)中,第 6 段被澄清为:
6 The array has the same lifetime as any other temporary object (12.2), except that initializing an initializer_list
object from the array extends the lifetime of the array exactly like binding a reference to a temporary.
通过 CWG issue 1290 的决议。这种澄清使得无法使用 initializer_list
作为例如 C++11 的意图的成员变量。但是,即使在 C++14 中,您的程序也有未定义的行为。
考虑这个代码示例:
#include <initializer_list>
#include <iostream>
int main()
{
for(auto e: []()->std::initializer_list<int>{return{1,2,3};}())
std::cout<<e<<std::endl;
return 0;
}
我尝试用g++编译它(gcc版本4.9.2(Debian 4.9.2-10)) 并且输出是正确的。 在 clang++ (Debian clang version 3.5.0-9 (tags/RELEASE_350/final) (based on LLVM 3.5.0)) 中输出例如:
0
2125673120
32546
其中第一行始终为 0,最后两行为 "random".
是clang的错误还是别的什么?我认为这个代码示例是正确的。
更新:
当 lambda 函数 return 类型为其他类型(例如 std::vector 或 std::array)时,此代码工作正常。
在 C++11 中,不保证底层数组在原始初始化列表对象的生命周期结束后仍然存在。因此,您的代码可能会出现未定义的行为。切换到 C++14。
来自 C++11 8.5.4 列表初始化 [dcl.init.list]:
5 An object of type
std::initializer_list<E>
is constructed from an initializer list as if the implementation allocated an array ofN
elements of typeE
, whereN
is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and thestd::initializer_list<E>
object is constructed to refer to that array. If a narrowing conversion is required to initialize any of the elements, the program is ill-formed.6 The lifetime of the array is the same as that of the
initializer_list
object.
你的 lambda 的 return
语句初始化了一个临时的 std::initializer_list<int>
和 returns 的副本。这一切都很好,除了它所引用的数组的生命周期在完整表达式的末尾结束。通过 lambda 外部的 initializer_list
访问死数组会导致未定义的行为。
initializer_list
不是容器,它是对临时容器的引用。如果你想把它当作一个容器来使用,你会很不愉快。
在 C++14(引用 N4140)中,第 6 段被澄清为:
6 The array has the same lifetime as any other temporary object (12.2), except that initializing an
initializer_list
object from the array extends the lifetime of the array exactly like binding a reference to a temporary.
通过 CWG issue 1290 的决议。这种澄清使得无法使用 initializer_list
作为例如 C++11 的意图的成员变量。但是,即使在 C++14 中,您的程序也有未定义的行为。