7

在 C++11 标准中,有一条关于支持统一初始化的数组的说明:

如果可以分配具有相同初始值设定项的显式数组,则该实现可以在只读内存中自由分配数组。

GCC/Clang/VS 是否利用了这一点?还是每次使用此功能的初始化都受堆栈上的其他数据以及此隐藏数组的额外初始化时间的影响?

例如,给定以下示例:

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

上面提到的每个编译器是否会将支持数组存储到与声明的变量相同的内存中的统一初始化中static const?并且每个编译器会在调用函数时或在应用程序初始化时初始化支持数组吗?(我不是在谈论std::initializer_list<std::string>将要创建的那个,而是它所指的“隐藏数组”。

4

2 回答 2

2

这是我至少为 GCC 回答我自己的问题的尝试。我对 gcc 的汇编程序输出的理解不是很好,所以请根据需要更正。

使用initializer_test.cpp

#include <vector>

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

并使用以下命令行使用 gcc v4.6.3 进行编译:

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

我得到以下输出(减少到希望相关的位):

   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()  #

 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 

现在,如果我在 x86-64 System V AMD64 ABI 调用约定(我已在代码清单中注释的参数)的上下文中正确理解第 109 行的调用,则表明支持数组存储在.rodata,我将其视为与静态 const 数据相同的内存。无论如何,至少对于 gcc 4.6。

执行类似的测试,但打开了优化 ( -O2) 似乎initializer_list已优化:

  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*)  #

总而言之,std::initializer_list在 gcc 中看起来非常理想。

于 2012-09-25T15:23:47.607 回答
-2

First of all: VC++, as of version VS11=VS2012 in its initial release does not support initializer lists, so the question is a bit moot for VS atm., but as I'm sure they'll patch this up, it should become relevant in a few months (or years).

As additional info, I'll add what VS 2012 does with local array initialization, everybody may draw it's own conclusion as for what that means for when they'll implement initializer lists:

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

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  

...

So this array is created/filled at function execution, no "static" storage involved as such.

于 2012-09-23T17:19:40.063 回答