簡體   English   中英

C++ 具有聚合初始化的常量匿名實例

[英]C++ Constant anonymous instance with aggregate initialization

基本上我想獲取一個常量和匿名 object 的指針,例如用T {x, y, z...}初始化的 class、數組或結構的實例。 對不起,我的措辭技巧很差。

我嘗試編寫的基本代碼如下:

//Clunky, Im sure there is an inbuilt class that can replace this, any information would be a nice addition
template<class T> class TerminatedArray {
public:
  T* children;
  int length;

  TerminatedArray(const T* children) {
    this->children = children;
    length = 0;
    while ((unsigned long)&children[length] != 0)
      length++;
  }
  TerminatedArray() {
    length = 0;
    while ((unsigned long)&children[length] != 0)
      length++;
  }
  const T get(int i) {
    if (i < 0 || i >= length)
      return 0;
    return children[i];
  }
};

const TerminatedArray<const int> i = (const TerminatedArray<const int>){(const int[]){1,2,3,4,5,6,0}};

class Settings {
public:
  struct Option {
    const char* name;
  };
  struct Directory {
    const char* name;
    TerminatedArray<const int> const children;
  };

  const Directory* baseDir;
  const TerminatedArray<const Option>* options;

  Settings(const Directory* _baseDir, const TerminatedArray<const Option> *_options);
};


//in some init method's:
Settings s = Settings(
  &(const Settings::Directory){
    "Clock",
    (const TerminatedArray<const int>){(const int[]){1,2,0}}
  },
  &(const TerminatedArray<const Settings::Option>){(const Settings::Option[]){
    {"testFoo"},
    {"foofoo"},
    0
  }}
);

我引用的代碼位於最底部,即s的定義。 我似乎能夠初始化一個常量整數數組,但是當將相同的技術應用於類時,它失敗了:
error: taking address of temporary [-fpermissive]

我什至不知道 C++ 是否支持這樣的事情,我想避免必須有單獨的 const 定義弄臟和拆分代碼,而是讓它們干凈和匿名。

想要將所有這些定義作為常量的原因是我正在從事一個 Arduino 項目,該項目需要 SRAM 與 Flash 的有效平衡。 而且我有很多 Flash 可供我使用。


我的問題是這個。 如何使用聚合初始化聲明一個常量匿名類/結構?

TerminatedArray直接(和更好)等效的是std::initializer_list

class Settings {
public:
  struct Option {
    const char* name;
  };
  struct Directory {
    const char* name;
    std::initializer_list<const int> const children;
  };

  const Directory* baseDir;
  const std::initializer_list<const Option>* options;

  Settings(const Directory& _baseDir, const std::initializer_list<const Option>& _options);
};


//in some init method's:
Settings s = Settings(
  {
    "Clock",
    {1,2,0}
  },
  {
    {"testFoo"},
    {"foofoo"}
  }
);

https://godbolt.org/z/8t7j0f

但是,這幾乎肯定會產生生命周期問題(編譯器試圖通過“獲取臨時地址”來警告您)。 如果您想存儲(非擁有)指針(或引用),那么其他人應該擁有 object 的所有權。 但是當用這樣的臨時對象初始化時,沒有其他人這樣做。 臨時對象在完整表達式結束時死亡,因此您存儲的指針現在指向死對象。 解決這個問題是另一回事(可能會使您的要求發生沖突)。

有點相關,我不確定將std::initializer_list存儲為 class 成員是否是一個好主意。 但這當然可以用作 function 參數來使聚合初始化更好。

&children[length] != 0仍然是 true 或 UB。

如果您不想分配 memory,您可以參考現有數組:

class Settings {
public:
  struct Option {
    const char* name;
  };
  struct Directory {
    const char* name;
    std::span<const int> const children;
  };

  const Directory baseDir;
  const std::span<const Option> options;

  Settings(Directory baseDir, span<const Option> options);
};

//in some method:
const std::array<int, 3> ints{{1,2,0}};
const std::array<Settings::Option> options{{"testFoo"}, {"foofoo"}};
Settings s{"Clock", {ints}}, options};

首先,你沒有聚合初始化任何東西。 這是統一初始化,您調用的是構造函數,而不是直接初始化成員。 這是因為您的類具有用戶定義的構造函數,而具有構造函數的類不能聚合初始化。

其次,您並不能真正“初始化一個常量整數數組”。 它只是編譯。 嘗試運行它會給出未定義的行為 - 在我的情況下,嘗試構造i會無限搜索元素值 0。

在 C++ 中,堆棧上有值,堆上有值,還有臨時值(我真的向知道 C++ 的人為此聲明道歉)。

  • 堆上的值具有可以自由傳遞的永久地址。
  • 堆棧上的值具有在塊結束之前有效的臨時地址。
  • 臨時值要么沒有地址(正如你的編譯器警告你的那樣),要么在它們用於的表達式的持續時間內有一個有效的地址。

您正在使用這樣的臨時來初始化i ,並嘗試存儲和使用臨時地址。 這是一個錯誤,如果你不打算在你的數組所在的塊之外使用i ,你可以在堆棧上創建你的“臨時”數組來修復它。

或者你可以在堆上創建你的數組,使用它的地址來初始化i ,並記住在你完成后顯式地刪除你的數組。

我建議在嘗試修復此代碼之前閱讀https://isocpp.org/faq並熟悉變量的生命周期和 memory 管理。 它應該讓你更好地了解你需要做什么才能讓你的代碼做你想做的事情。

祝你好運。

暫無
暫無

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

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