GCC的实现破坏了std::initializer_list返回full-expression结束时从函数返回的数组.它是否正确?
此程序中的两个测试用例都显示在使用值之前执行的析构函数:
#include <initializer_list>
#include <iostream>
struct noisydt {
~noisydt() { std::cout << "destroyed\n"; }
};
void receive( std::initializer_list< noisydt > il ) {
std::cout << "received\n";
}
std::initializer_list< noisydt > send() {
return { {}, {}, {} };
}
int main() {
receive( send() );
std::initializer_list< noisydt > && il = send();
receive( il );
}
Run Code Online (Sandbox Code Playgroud)
我认为该计划应该有效.但潜在的标准有点令人费解.
return语句初始化一个返回值对象,就像它被声明一样
std::initializer_list< noisydt > ret = { {},{},{} };
Run Code Online (Sandbox Code Playgroud)
这initializer_list将从给定的初始化器系列初始化一个临时及其底层数组存储,然后initializer_list从第一个初始化器初始化另一个.阵列的寿命是多少?"数组的生命周期与initializer_list对象的生命周期相同." 但其中有两个; 哪一个是模棱两可的.8.5.4/6中的示例(如果它按照公布的方式工作)应该解决数组具有复制到对象的生命周期的歧义.然后返回值的数组也应该存在于调用函数中,并且应该可以通过将它绑定到命名引用来保留它.
我在带有 GCC 9.3.0 的 Debian 不稳定版上运行。
最近我参与的一个项目发生了变化,引入了类似于下面的代码。
#include <initializer_list>
#include <map>
#include <vector>
std::map<int, std::vector<int>> ex = []{
/* for reused lists */
std::initializer_list<int> module_options;
return (decltype(ex)) {
{1, module_options = {
1, 2, 3
}},
{2, module_options},
};
}();
Run Code Online (Sandbox Code Playgroud)
这个想法是初始化列表的相同子部分首先在顶部声明,std:initializer_list在第一次使用时定义并分配给变量,然后在多个地方使用。这很方便,有些人可能会争辩说更具可读性,这就是它被接受的原因。
一切都很好,直到几天前 GCC 开始init-list-lifetime对代码发出警告。我们-Werror在回归中使用,所以这对我来说回归失败了。我还尝试使用 clang 9.0.1 进行编译,但不会引发警告。
<source>: In lambda function:
<source>:12:9: warning: assignment from temporary 'initializer_list' does not extend the lifetime of the underlying array [-Winit-list-lifetime]
12 | }},
| ^
Run Code Online (Sandbox Code Playgroud)