繁体   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