簡體   English   中英

default構造函數是否初始化成員數組變量?

[英]Does default constructor zero-initialize member array variable?

當我用它的輸出檢查下面的程序時,我發現通過返回值獲取FrameA對象非常困惑:

  1. 定義空ctor,成員數組字段保持未初始化
  2. 讓編譯器生成ctor時,成員數組字段被初始化為全0

     auto a = f(); // f() --> return A(); 

鑒於以下SSCCE

#include <cstring>
#include <iostream>
#include <chrono>
#include <algorithm>

using namespace std;

const int MAX = 9999999;

struct FrameA {
  // FrameA() {}
  // FrameA(const FrameA &v) { memcpy(data, v.data, sizeof(data)); }
  char data[1000];
};

FrameA f(int i) { return FrameA(); }

int test(int odd) {
  int sum = 0;
  auto begin = chrono::steady_clock::now();
  for (int i = 0; i < MAX; ++i) {
    auto v = f(odd);
    sum += v.data[0] + v.data[330];
  }
  auto end = chrono::steady_clock::now();
  cout << chrono::duration_cast<chrono::milliseconds>(end - begin).count()
       << " (milliseconds)" << endl;
  return sum;
}

int _tmain(int argc, _TCHAR *argv[]) {
  test(0);
  test(1);
  return 0;
}

定義空ctor時,輸出如下:

g ++ v4.8.1

72(毫秒)
73(毫秒)

但是使用編譯生成的ctor,輸出是:

g ++ v4.8.1

1401(毫秒)
1403(毫秒)

我也在VC12上測試過,結果很相似。

檢查程序集后,我發現在使用編譯器生成的ctor時:

  for (int i = 0; i < MAX; ++i) {
    auto v = f(odd);
00A31701  push        3E8h  
00A31706  lea         eax,[ebp-3F8h]  
00A3170C  push        0  
00A3170E  push        eax  
00A3170F  call        _memset (0A32460h)               ;; memset FrameA to 0
    sum += v.data[0] + v.data[330];
00A31714  movsx       eax,byte ptr [ebp-3F8h] 

但是使用空ctor不會調用memset將FrameA中的數組設置為零。

這有什么解釋嗎?

順便說一句,我搜索了C ++ 11草案n3242,但是第8章zero-initializedefault-initialize似乎並沒有涵蓋這種情況。 我錯過了什么嗎?

FrameA()將對對象進行值初始化(§5.2.3/ 2):

表達式T() ,其中T是非數組完整對象類型的簡單類型說明符類型名稱說明 ,或者(可能是cv限定的) void類型,創建指定類型的prvalue,它是值 -初始化

初始化沒有用戶提供的構造函數的非聯合類類型的值將對其進行零初始化(第8.5 / 7節):

如果T是一個(可能是cv限定的)非聯合類類型而沒有用戶提供的構造函數,那么該對象是零初始化的,如果T的隱式聲明的默認構造函數是非平凡的,則調用該構造函數。

這將零初始化其每個成員。

初始化具有用戶提供的構造函數的類類型將簡單地調用構造函數(在您的情況下,不會初始化數組)(§8.5/ 7):

如果T是具有用戶提供的構造函數(12.1)的(可能是cv限定的)類類型(第9節),則調用T的默認構造函數(如果T沒有可訪問的默認構造函數,則初始化是錯誤的) ;

使用默認構造函數構造類型為T的對象時,即使用T()您將獲得值初始化默認構造,具體取決於T的定義方式:

  1. 如果T沒有默認構造函數或者具有默認的默認構造函數,則編譯器負責初始化:編譯器值初始化所有成員。 對於內置類型值初始化意味着它是零初始化的 ,即,值接收它們對應的合適的零表示。
  2. 如果T具有非默認的默認構造函數,則T的程序員接管初始化成員的責任。 成員要么在成員初始化列表中列出並相應地初始化,要么默認初始化 內置類型的默認初始化意味着沒有任何反應,即這些成員未初始化。

A()使用值初始化 正如您所注意到的,這取決於A是否具有用戶聲明的默認構造函數。

  • 如果是,則調用。 未由構造函數顯式初始化的任何成員將保持未初始化狀態。 對於像這樣的自動或臨時對象,這意味着它們不會被觸及,並且將包含發生在內存中的任何垃圾。
  • 如果沒有,則每個成員都將初始化值。 對於大多數基本類型,值初始化將它們設置為零。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM