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;
}

そして、次のコマンドラインを使用してgccv4.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。これは静的定数データと同じメモリであると考えています。とにかく少なくともgcc4.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_listgccではかなり最適に見えます。

于 2012-09-25T15:23:47.607 に答える
-2

まず第一に:VC ++、初期リリースのバージョンVS11 = VS2012は初期化リストをサポートしていないので、質問はVS atmには少し議論の余地がありますが、これを修正すると確信しているので、次のようになります。数ヶ月(または数年)で関連します。

追加情報として、VS 2012がローカル配列の初期化で行うことを追加します。初期化リストを実装するときの意味については、誰もが独自の結論を導き出すことができます。

release mode組み込みアレイの初期化は、VC++2012がコンパイラのデフォルトで吐き出すものです。

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  

...

したがって、この配列は関数の実行時に作成/入力され、「静的」ストレージ自体は含まれません。

于 2012-09-23T17:19:40.063 に答える