简体   繁体   English

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

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

Basically Im wanting to fetch a pointer of a constant and anonymous object, such as an instance of a class, array or struct that is inialised with T {x, y, z...} .基本上我想获取一个常量和匿名 object 的指针,例如用T {x, y, z...}初始化的 class、数组或结构的实例。 Sorry for my poor skills in wording.对不起,我的措辞技巧很差。

The basic code that Im trying to write is as follows:我尝试编写的基本代码如下:

//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
  }}
);

The code that I refer to is at the very bottom, the definition of s .我引用的代码位于最底部,即s的定义。 I seem to be able to initialize a constant array of integers, but when applying the same technique to classes, it fails with:我似乎能够初始化一个常量整数数组,但是当将相同的技术应用于类时,它失败了:
error: taking address of temporary [-fpermissive]

I don't even know if C++ supports such things, I want to avoid having to have separate const definitions dirtying and splitting up the code, and instead have them clean and anonymous.我什至不知道 C++ 是否支持这样的事情,我想避免必须有单独的 const 定义弄脏和拆分代码,而是让它们干净和匿名。

The reason for wanting all these definitions as constants is that Im working on an Arduino project that requires efficient balancing of SRAM to Flash.想要将所有这些定义作为常量的原因是我正在从事一个 Arduino 项目,该项目需要 SRAM 与 Flash 的有效平衡。 And I have a lot of Flash to my disposal.而且我有很多 Flash 可供我使用。


My question is this.我的问题是这个。 How can I declare a constant anonymous class/struct using aggregate initialization?如何使用聚合初始化声明一个常量匿名类/结构?

The direct (and better) equivalent to TerminatedArray is std::initializer_list :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 https://godbolt.org/z/8t7j0f

However, this will almost certainly have lifetime issues (which the compiler tried to warn you about with "taking address of temporary").但是,这几乎肯定会产生生命周期问题(编译器试图通过“获取临时地址”来警告您)。 If you want to store a (non-owning) pointer (or reference) then somebody else should have ownership of the object.如果您想存储(非拥有)指针(或引用),那么其他人应该拥有 object 的所有权。 But when initializing with temporary objects like this, nobody else does.但是当用这样的临时对象初始化时,没有其他人这样做。 The temporaries die at the end of the full expression, so your stored pointers now point to dead objects.临时对象在完整表达式结束时死亡,因此您存储的指针现在指向死对象。 Fixing this is a different matter (possibly making your requirements conflicting).解决这个问题是另一回事(可能会使您的要求发生冲突)。

Somewhat relatedly, I'm not sure whether storing a std::initializer_list as class member is a good idea might.有点相关,我不确定将std::initializer_list存储为 class 成员是否是一个好主意。 But it's certainly the thing you can use as function parameter to make aggregate initialization nicer.但这当然可以用作 function 参数来使聚合初始化更好。

&children[length] != 0 is still true or UB. &children[length] != 0仍然是 true 或 UB。

If you don't want to allocate memory, you might take reference to existing array:如果您不想分配 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};

First, you're not aggregate-initializing anything.首先,你没有聚合初始化任何东西。 This is uniform initialization and you're calling constructors instead of directly initializing members.这是统一初始化,您调用的是构造函数,而不是直接初始化成员。 This is because your classes have user-defined constructors, and classes with constructors can't be aggregate-initialized.这是因为您的类具有用户定义的构造函数,而具有构造函数的类不能聚合初始化。

Second, you're not really able to "initialize a constant array of integers".其次,您并不能真正“初始化一个常量整数数组”。 It merely compiles.它只是编译。 Trying to run it gives undefined behavior - in my case, trying to construct i goes into an infinite search for element value 0.尝试运行它会给出未定义的行为 - 在我的情况下,尝试构造i会无限搜索元素值 0。

In C++, there's values on the stack, there's values on the heap and there's temporary values (I genuinely apologize to anyone who knows C++ for this statement).在 C++ 中,堆栈上有值,堆上有值,还有临时值(我真的向知道 C++ 的人为此声明道歉)。

  • Values on the heap have permanent addresses which you can pass around freely.堆上的值具有可以自由传递的永久地址。
  • Values on the stack have temporary addresses which are valid until the end of the block.堆栈上的值具有在块结束之前有效的临时地址。
  • Temporary values either don't have addresses (as your compiler warns you) or have a valid address for the duration of the expression they're used for.临时值要么没有地址(正如你的编译器警告你的那样),要么在它们用于的表达式的持续时间内有一个有效的地址。

You're using such a temporary to initialize i , and trying to store and use the address of a temporary.您正在使用这样的临时来初始化i ,并尝试存储和使用临时地址。 This is an error and to fix it you can create your "temporary" array on the stack if you don't plan to use i outside of the block where your array will be.这是一个错误,如果你不打算在你的数组所在的块之外使用i ,你可以在堆栈上创建你的“临时”数组来修复它。

Or you can create your array on the heap, use its address to initialize i , and remember to explicitly delete your array when you're done with it.或者你可以在堆上创建你的数组,使用它的地址来初始化i ,并记住在你完成后显式地删除你的数组。

I recommend reading https://isocpp.org/faq and getting familiar with lifetime of variables and memory management before attempting to fix this code.我建议在尝试修复此代码之前阅读https://isocpp.org/faq并熟悉变量的生命周期和 memory 管理。 It should give you a much better idea of what you need to do to make your code do what you want it to do.它应该让你更好地了解你需要做什么才能让你的代码做你想做的事情。

Best of luck.祝你好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM