Storage of the "hidden array" behind the initializer_list parameter

There is a note in the C ++ 11 standard regarding an array that supports uniform initialization, which states:

An implementation can freely allocate an array in read-only memory if an explicit array with the same initializer can be allocated like this.

Does GCC / Clang / VS use this? Or is each initialization using this function associated with additional data on the stack and additional initialization time for this hidden array?

For example, in the following example:

void function() { std::vector<std::string> values = { "First", "Second" }; ... 

If each of the above compilers stores an array of uniform initialization in the same memory as a variable declared static const ? And will each of the compilers initialize the base array when the function is called or when the application is initialized? (I'm not talking about std::initializer_list<std::string> that will be created, but rather about the "hidden array" that it refers to.

+7
source share
2 answers

This is my attempt to answer my question, at least on the GCC. My understanding of gcc assembler output is not fantastic, so please correct if necessary.

Using initializer_test.cpp :

 #include <vector> int main() { std::vector<long> values = { 123456, 123457, 123458 }; return 0; } 

And compiling using gcc v4.6.3 using the following command line:

 g++ -Wa,-adhln -g initializer_test.cpp -masm=intel -std=c++0x -fverbose-asm | c++filt | view - 

I get the following output (cut out for reliable bits):

  5:initializer_test.cpp **** std::vector<long> values = { 123456, 123457, 123458 }; 100 .loc 2 5 0 101 0009 488D45EF lea rax, [rbp-17] # tmp62, 102 000d 4889C7 mov rdi, rax #, tmp62 103 .cfi_offset 3, -24 104 0010 E8000000 call std::allocator<long>::allocator() # 104 00 105 0015 488D45D0 lea rax, [rbp-48] # tmp63, 106 0019 BA030000 mov edx, 3 #, <-- Parameter 3 106 00 107 001e BE000000 mov esi, OFFSET FLAT:._42 #, <-- Parameter 2 107 00 108 0023 4889C7 mov rdi, rax #, tmp63 <-- Parameter 1 109 0026 E8000000 call std::initializer_list<long>::initializer_list(long const*, unsigned long) # 109 00 110 002b 488D4DEF lea rcx, [rbp-17] # tmp64, 111 002f 488B75D0 mov rsi, QWORD PTR [rbp-48] # tmp65, D.10602 112 0033 488B55D8 mov rdx, QWORD PTR [rbp-40] # tmp66, D.10602 113 0037 488D45B0 lea rax, [rbp-80] # tmp67, 114 003b 4889C7 mov rdi, rax #, tmp67 115 .LEHB0: 116 003e E8000000 call std::vector<long, std::allocator<long> >::vector(std::initializer_list<long>, std::allocator<long> const&) # 116 00 117 .LEHE0: 118 .loc 2 5 0 is_stmt 0 discriminator 1 119 0043 488D45EF lea rax, [rbp-17] # tmp68, 120 0047 4889C7 mov rdi, rax #, tmp68 121 004a E8000000 call std::allocator<long>::~allocator() # 

and

  1678 .section .rodata 1679 0002 00000000 .align 16 1679 00000000 1679 00000000 1679 0000 1682 ._42: 1683 0010 40E20100 .quad 123456 1683 00000000 1684 0018 41E20100 .quad 123457 1684 00000000 1685 0020 42E20100 .quad 123458 1685 00000000 

Now, if I understand correctly the call on line 109 in the context of the x86-64 System V AMD64 ABI call convention (the parameters that I annotated to list the code), this shows that the underlying array is stored in .rodata , which I accept as the same memory, as well as static constant data. At least for gcc 4.6.

Performing a similar test, but with optimizations enabled ( -O2 ), initializer_list seems to be optimized:

  70 .file 2 "/usr/include/c++/4.6/ext/new_allocator.h" 71 .loc 2 92 0 72 0004 BF180000 mov edi, 24 #, 72 00 73 0009 E8000000 call operator new(unsigned long) # 73 00 74 .LVL1: 75 .file 3 "/usr/include/c++/4.6/bits/stl_algobase.h" 76 .loc 3 366 0 77 000e 488B1500 mov rdx, QWORD PTR ._42[rip] # ._42, ._42 77 000000 90 .file 4 "/usr/include/c++/4.6/bits/stl_vector.h" 91 .loc 4 155 0 92 0015 4885C0 test rax, rax # D.11805 105 .loc 3 366 0 106 0018 488910 mov QWORD PTR [rax], rdx #* D.11805, ._42 107 001b 488B1500 mov rdx, QWORD PTR ._42[rip+8] # ._42, ._42 107 000000 108 0022 48895008 mov QWORD PTR [rax+8], rdx #, ._42 109 0026 488B1500 mov rdx, QWORD PTR ._42[rip+16] # ._42, ._42 109 000000 110 002d 48895010 mov QWORD PTR [rax+16], rdx #, ._42 124 .loc 4 155 0 125 0031 7408 je .L8 #, 126 .LVL3: 127 .LBB342: 128 .LBB343: 129 .loc 2 98 0 130 0033 4889C7 mov rdi, rax #, D.11805 131 0036 E8000000 call operator delete(void*) # 

In general, std::initializer_list looks pretty optimal in gcc.

+2
source

First of all: VC ++, starting with version VS11 = VS2012, in its initial version does not support initializer lists, so the question is a bit of a debate for VS atm., But, as I am sure, they will fix this, it should become relevant within a few months (or years).

As an additional information, I will add what VS 2012 does with initializing a local array, everyone can draw their own conclusion, as this means when they will implement initializer lists:

Here's the initialization of the built-in arrays that VC ++ 2012 spits out by default the compiler release mode :

 int _tmain(int argc, _TCHAR* argv[]) { 00B91002 in al,dx 00B91003 sub esp,28h 00B91006 mov eax,dword ptr ds:[00B94018h] 00B9100B xor eax,ebp 00B9100D mov dword ptr [ebp-4],eax 00B91010 push esi int numbers[] = {1,2,3,4,5,6,7,8,9}; 00B91011 mov dword ptr [numbers],1 00B91018 mov dword ptr [ebp-24h],2 00B9101F mov dword ptr [ebp-20h],3 00B91026 mov dword ptr [ebp-1Ch],4 00B9102D mov dword ptr [ebp-18h],5 00B91034 mov dword ptr [ebp-14h],6 00B9103B mov dword ptr [ebp-10h],7 00B91042 mov dword ptr [ebp-0Ch],8 00B91049 mov dword ptr [ebp-8],9 ... 

Thus, this array is created / filled during the execution of the function; no static storage is used as such.

-2
source

All Articles