簡體   English   中英

C++11:賦值運算符是否會阻止類型被 POD 並因此被全局初始化?

[英]C++11: Does an assignment operator prevent a type from being POD, and thus being global-initialized?

背景:我在一個大代碼環境中,其中運行全局構造函數的未定義順序是有問題的。 所以我有一個自定義類,旨在將初始化延遲到第一次使用。 它所有的魔法都發生在它的 operator* 和 operator-> 函數中; 它們是唯一定義的東西。 它還在自身內部存儲一些狀態,以供自動初始化功能使用。 那個狀態當然必須是POD,這樣整個類都是POD,這樣它就可以在任何人的代碼開始運行之前完全設置好,這樣到處的所有代碼都可以到處使用所有的全局變量,而不必擔心全局變量沒有'還沒有設置。

不久前,有人添加了一個私有的、從未定義的賦值運算符,因此該類型永遠不會被賦值(無論如何它都不會被設計為永遠改變)。 現在有人說這個類壞了,因為它不是 POD。 如果不是聲明但未定義,而是將其聲明為“=delete”,我認為這樣會更好。 事實上,隨着這種變化, std::is_pod<>​​::value 為該類型返回 true 。

但是 as 賦值運算符會阻止類型成為 POD 嗎? 我認為要求只是它必須只有公共數據成員,沒有虛方法,也沒有構造函數或析構函數。

更重要的是,對於我的情況:從未定義的賦值運算符的存在是否會阻止類在全局初始化時與所有其他全局 POD 一起被初始化?

簡化示例:

struct LazyString {
  const char *c_str;

  bool has_been_inited;
  string *lazy_str_do_not_use_directly;

  string &operator*() { return *get(); }
  string *operator->() { return get(); }

 private:
  string *get() {
    // The real code uses a mutex, of course, to be thread-safe.
    if (!has_been_inited) {
      lazy_str_do_not_use_directly = new string(c_str);
      has_been_inited = true;
    }
    return lazy_str_do_not_use_directly;
  }

  // Does this make the class non-POD?
  // If so, does that mean that global variables of this type
  // will not be initialized at global-initialization time, that wonderful
  // moment in time where no code has yet been run?
  void operator=(const LazyString&);

  // If I do this instead, it breaks C++03 compatibility, but is this somehow better?
  void operator=(const LazyString&) = delete;
};

LazyString lazy = { "lazy" };

int main(int argc, char *argv[]) {
  std::cout << *lazy;
}

賦值運算符是否會阻止類型成為 POD

是的。 POD 類型必須是平凡的 因此必須是可簡單復制的 因此必須沒有非平凡的復制或移動賦值運算符。

任何用戶提供的運算符都是重要的,因此聲明復制構造函數會使類變得重要,因此非 POD。

從而被全局初始化?

不。任何可實例化的類型,無論是否為 POD,都可以是全局變量。

更新:從評論中,你的意思是問:

它可以靜態初始化,而不是動態初始化嗎?

是的,因為它有一個簡單的構造函數; 只要初始化器是一個常量表達式。 在您的示例中, { "lazy" }是一個常量表達式,因此可以靜態初始化LazyString

這里的重要特性是它有一個簡單的構造函數,而不是它的 POD。 POD 意味着它還滿足各種其他要求,與初始化無關。

對於具有靜態存儲持續時間的非局部變量(全局變量屬於這一類),C++ 有幾個初始化階段——無論類型是否為 POD。

  • 零初始化發生在任何其他初始化之前
  • 持續初始化
  • 動態初始化

前兩種類型的初始化必須在動態初始化之前進行。 動態初始化是初始化順序很難設置的情況。 一些動態初始化是無序的,一些是在翻譯單元內有序的,等等。

即使您的全局變量不是 POD,您也可以確保在任何動態初始化之前已經進行了零初始化。

有關詳細信息,請參閱 C++11 3.6.2“非局部變量的初始化”。

暫無
暫無

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

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