S
SG
Hi!
In a Google tech talk, Bjarne Stroustrup answered an audience question
about whether it is possible to return std::initializer_list objects
from functions with "Yes.". However, after having read the relevant
sections of the recent draft (N3090.pdf)...
section 8.5.4 ("List initialization"):
4 An object of type std::initializer_list<E> is constructed from an
initializer list as if the implementation allocated an array of N
elelemts 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. [...] [Example:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
The initialization will be implemented in a way roughly equivalent
to this:
double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
assuming that the implementation can construct an initializer_list
object with a pair of pointers. -end example ]
5 The lifetime of the array is the same as that of the
initializer_list object. [ Example:
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 };
}
For v1 and v2, the initializer_list object and array created for
{ 1, 2, 3 } have full-expression lifetime. For i3, the
initializer_list object and array have automatic lifetime.
-end example ] [ Note: The implementation is free to allocate the
array in read-only memory if an explicit array with the same
initializer could be so allocated. —end note ]
section 18.9 ("Initializer lists")
2 [...] Copying an initializer list does not copy the underlying
elements.
....I have trouble figuring out whether Stroustrup was right or wrong.
The standard doesn't require the compiler to store the array
statically initialized in a read-only section. So, in the worst case
the array has automatic storage and the array will be destroyed before
the function returns (see implementation example from 8.5.4/4).
std::initializer_list<double> foo() {
return {1.0, 3.0};
}
equivalent to
std::initializer_list<double> foo() {
double __ila[2] = {1.0,3.0};
return std::initializer_list<double>(ila,ila+2);
}
?
But this would be a contradiction to 8.5.4/5 because the life-time of
the std::initializer_list surpasses the life-time of the array in this
case -- at least when copy elision (RVO) is applied.
So, my question is:
Is returning an initializer_list from a function actually supposed to
work reliably?
I'm guessing the answer is "no".
Cheers!
SG
In a Google tech talk, Bjarne Stroustrup answered an audience question
about whether it is possible to return std::initializer_list objects
from functions with "Yes.". However, after having read the relevant
sections of the recent draft (N3090.pdf)...
section 8.5.4 ("List initialization"):
4 An object of type std::initializer_list<E> is constructed from an
initializer list as if the implementation allocated an array of N
elelemts 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. [...] [Example:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
The initialization will be implemented in a way roughly equivalent
to this:
double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
assuming that the implementation can construct an initializer_list
object with a pair of pointers. -end example ]
5 The lifetime of the array is the same as that of the
initializer_list object. [ Example:
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 };
}
For v1 and v2, the initializer_list object and array created for
{ 1, 2, 3 } have full-expression lifetime. For i3, the
initializer_list object and array have automatic lifetime.
-end example ] [ Note: The implementation is free to allocate the
array in read-only memory if an explicit array with the same
initializer could be so allocated. —end note ]
section 18.9 ("Initializer lists")
2 [...] Copying an initializer list does not copy the underlying
elements.
....I have trouble figuring out whether Stroustrup was right or wrong.
The standard doesn't require the compiler to store the array
statically initialized in a read-only section. So, in the worst case
the array has automatic storage and the array will be destroyed before
the function returns (see implementation example from 8.5.4/4).
std::initializer_list<double> foo() {
return {1.0, 3.0};
}
equivalent to
std::initializer_list<double> foo() {
double __ila[2] = {1.0,3.0};
return std::initializer_list<double>(ila,ila+2);
}
?
But this would be a contradiction to 8.5.4/5 because the life-time of
the std::initializer_list surpasses the life-time of the array in this
case -- at least when copy elision (RVO) is applied.
So, my question is:
Is returning an initializer_list from a function actually supposed to
work reliably?
I'm guessing the answer is "no".
Cheers!
SG