簡體   English   中英

我可以阻止非POD類中數組數據成員中元素的零初始化嗎?

[英]Can I prevent zero initialization of the elements in an array data member in a non-POD class?

非POD派生類PayloadMessage包含一個數組數據成員(_payload),其元素似乎在構造時初始化為零。 出於性能/效率的原因,我不希望這種情況發生 - 它是一個龐大的陣列。 建議? (可能是新的布局?)我使用的是舊的g ++編譯器,3.4.6。

#include <iostream>
class BaseMessage {
public:
  enum CCC_MessageType {  START_THREAD, KILL_THREAD };
  CCC_MessageType _type;
  virtual ~BaseMessage() {}  // class has other non-POD class stuff
};
class PayloadMessage : public virtual BaseMessage {
public:
  uint16_t _payload_length;
  uint8_t  _payload[3000];
};
int main(int argc, char* argv[]) {
  PayloadMessage* m = new PayloadMessage;
  size_t i = 0;
  for(; i < 3000; i++) { 
    std::cout << ' ' <<  static_cast<int>(m->_payload[i]); // all zeros, not what I want
  }
}

編輯:好的,基於評論/答案和一些測試(如下所示),數組未被初始化。 (有誰知道什么可能導致內存看起來被排除在外?)

為了進行性能測試,我將main()更改為以下內容:

int main(int argc, char* argv[]) {
  PayloadMessage* m = new PayloadMessage;
  size_t i = 0;
  for(; i < 1400000; i++) {  // allocates just under 4GB, for 32-bit compatibility
    m = new PayloadMessage;
  }
}

然后編譯並運行定時測試:

$ g++ -O3 test.cpp
$ time ./a.out
real    0m7.068s
user    0m1.393s
sys     0m4.730s

然后我添加了一個構造函數來為_payload進行顯式值初始化並再次運行測試:

PayloadMessage() : _payload() {}

$ g++ -O3 test.cpp
$ time ./a.out
real    0m10.361s
user    0m3.582s
sys     0m5.797s

是的,具有顯式初始化的第二個版本需要更長時間,因此我假設第一個版本沒有進行初始化(它只是看起來那樣)。 感謝你的幫助。

POD僅在使用() (C ++標准中為8.5 ()時顯式初始化值,否則默認初始化。 POD的默認初始化意味着它對內存沒有任何作用。 如果operator new返回零初始化內存,那么PayloadMessage的構造函數不會執行任何額外的工作。 出於好奇,您是否檢查了PayloadMessage的構造函數的反匯編,以確定它是否實際上做了任何昂貴的事情?

沒有理由將這個數組初始化為零:我認為你應該查看你的特定實現的文檔(可能是調試選項?)。

您可以使用std::vectorpush_back (可選擇使用reserve )嗎? 這允許您在需要時准確構造對象。

編輯:這也消除了對長度變量的需要。

編輯2:假設您當前的代碼正常工作,您是否實際通過分析確認初始化實際上是代碼中的瓶頸? 這可能嚴格地說是過早優化。

在編輯中回答你的問題“有沒有人知道什么可能導致內存看起來被歸零?”

您正在分配大量內存,因此operator new正在從操作系統請求新的虛擬內存塊。 作為安全功能,所有當前操作系統都確保在進程可以讀取之前清除虛擬分配的內存。 這是為了確保進程隔離,以便您無法讀取先前寫入並由另一個進程釋放的內存。

無法在第一次訪問時避免內存變為清零,但您可以使用自定義內存分配器來重用從操作系統請求的虛擬內存池。 這將允許后續請求避免清除。 保持虛擬內存與operator delete的默認行為相反,即將虛擬內存返回給操作系統以進行大量分配。 也可以在執行虛擬分配和解除分配時調整默認分配器的閾值,但這取決於系統。

暫無
暫無

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

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