GCC的实现销毁std::initializer_list
在返回全表达年底从函数返回数组。 它是否正确?
测试案例在该程序显示值之前执行析构函数,可以使用:
#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 );
}
我认为程序应该工作。 但底层standardese是一个有点令人费解。
return语句初始化一个返回值的对象,如果它被宣布
std::initializer_list< noisydt > ret = { {},{},{} };
这将初始化一个临时initializer_list
和从给定的一系列初始化的其底层阵列存储,然后初始化另一个initializer_list
从第一个。 什么是数组的一生? “阵列的寿命是相同的的initializer_list
对象”。 但有两个那些; 哪一个是不明确的。 在8.5.4 / 6的例子中,如果它作为宣传的,应解决的阵列具有的复制到对象寿命的模糊性。 然后返回值的数组也应该活到调用函数,它应该能够通过其绑定到一个名为参考保存它。
上LWS ,GCC错误地杀死阵列返回之前,但它保留了一个名为initializer_list
每示例。 锵还正确处理的例子,但在列表永远不会被销毁的对象; 这会导致内存泄漏。 ICC不支持initializer_list
的。
是我的分析是正确的?
C ++ 11§6.6.3/ 2:
有支撑,初始化列表 return语句初始化对象或引用从函数从指定的初始化列表复制列表初始化(8.5.4)返回。
8.5.4 / 1:
......在副本初始化上下文列表初始化被称为副本列表初始化 。
8.5 / 14:
发生在形式初始化
T x = a;
......被称为拷贝初始化 。
回到8.5.4 / 3:
对象或类型T的参考的列表的初始化被定义为如下:...
-否则,如果T是的特殊化
std::initializer_list<E>
一个initializer_list
对象,如下所述,并用于根据从一类同一类型的对象的初始化规则,以初始化该对象(8.5)构成。
8.5.4 / 5:
类型的对象
std::initializer_list<E>
如如果实现分配类型E的N个元素,其中N是在初始化列表中元素的数目的阵列是从初始化列表构造。 该数组的每个元素是复制初始化为初始化列表的相应元素,并且std::initializer_list<E>
对象被构造来指代阵列。 如果缩小转换是必需的初始化任何元素,是形成不良的节目。
8.5.4 / 6:
阵列的寿命是相同的的
initializer_list
对象。 [例:typedef std::complex<double> cmplx; std::vector<cmplx> v1 = { 1, 2, 3 }; void f() { std::vector<cmplx> v2{ 1, 2, 3 }; std::initializer_list<int> i3 = { 1, 2, 3 }; }
为
v1
和v2
时,initializer_list
对象和阵列createdfor{ 1, 2, 3 }
具有全表达寿命。 为i3
,所述initializer_list对象和阵列具有自动寿命。 -端示例]
有一点澄清返回支撑,初始化列表
当您返回大括号括起来的裸名单,
有支撑,初始化列表return语句初始化对象或引用从函数从指定的初始化列表复制列表初始化(8.5.4)返回。
这并不意味着该对象返回到调用范围从东西复制。 例如,这是有效的:
struct nocopy {
nocopy( int );
nocopy( nocopy const & ) = delete;
nocopy( nocopy && ) = delete;
};
nocopy f() {
return { 3 };
}
这不是:
nocopy f() {
return nocopy{ 3 };
}
复制清单初始化仅仅意味着该语法的等效nocopy X = { 3 }
被用于初始化表示的返回值的对象。 这不调用一个副本,它正好是相同的阵列的寿命被延长了8.5.4 / 6的例子。
而锵和GCC都同意这一点。
其他注意事项
的审查N2640不转了这种极端情况的任何提及。 已经有关于个人特点结合在这里广泛讨论,但我没有看到他们的互动事情。
实现此,因为它涉及到由值返回一个可选的,可变长度阵列得到有毛。 因为std::initializer_list
没有自己的内容,该功能必须也返回别的东西哪一样。 当传递给一个函数,这是一个简单的本地的,固定大小的数组。 但在其他方向上,VLA需要在堆栈上返回,与一起std::initializer_list
的指针。 然后调用者需要被告知是否处置序列(无论他们是在栈或没有)。
这个问题是很容易的从一个lambda函数返回一个支撑,初始化列表,作为一个“自然”的方式返回几个临时的对象,而不关心他们是如何对含有偶然发现。
auto && il = []() -> std::initializer_list< noisydt >
{ return { noisydt{}, noisydt{} }; }();
事实上,这是类似我如何到达这里。 但是,这将是一个错误离开了->
尾返回类型,因为拉姆达返回类型推演仅当表达式返回和支撑,初始化列表不是表达式发生。