I understand from here that std::initializer_list
doesn't need to allocate heap memory. Which is very strange to me since you can take in an std::initializer_list
object without specifying the size whereas for arrays you always need to specify the size. This is although initializer lists internally almost the same as arrays (as the post suggests).
What I have a hard time wrapping my head around is that with C++ as a statically typed language, the memory layout (and size) of every object must be fixed at compile time. Thus, every std::array
is another type and we just spawn those types from a common template. But for std::initializer_list
, this rule apparently doesn't apply, as the memory layout (while it can be derived from the arguments passed to its constructor) doesn't need to be considered for a receiving function or constructor. This makes sense to me only if the type heap allocates memory and only reserves storage to manage that memory. Then the difference would be much like std::array
and std::vector
, where for the later you also don't need to specify size.
Yet std::initializer_list
doesn't use heap allocations, as my tests show:
#include <string>
#include <iostream>
void* operator new(size_t size)
{
std::cout << "new overload called" << std::endl;
return malloc(size);
}
template <typename T>
void foo(std::initializer_list<T> args)
{
for (auto&& a : args)
std::cout << a << std::endl;
}
int main()
{
foo({2, 3, 2, 6, 7});
// std::string test_alloc = "some string longer than std::string SSO";
}
How is this possible? Can I write a similar implementation for my own type? That would really save me from blowing my binary whenever I play the compile time orchestra.
EDIT: I should note that the question I wanted to ask is not how the compiler knows what size it should instantiate the initializer list with (as can be achieved via template argument deduction) but how it is then not a different type from all the other instantiations of an initializer list (hence why you can pass initializer lists of different sizes to the same function).
std::initializer_list
cannot be implemented in standard C++. – Biospherestd::initializer_list
are like simple arrays under the hood. If you check the generated asm for your example (godbolt.org/z/vEoc46Pn9), you can see that your array is in the binary. You cannot implement it sincestd::initializer_list
is a special class "bounded" to the compiler. Just likeconstexpr construt_at
, you cannot implement that neither... – Reactivateint a[] = {1,2,3};
- the compiler knows. – Dulseaconst char s[] = "Hello World";
works the same way ands
decays to a simple pointer. Orconst char *s = "Hello World";
. – Remediable