C++静态初始化:折叠结构

C++静态初始化:折叠结构,c++,optimization,static,initialization,static-members,C++,Optimization,Static,Initialization,Static Members,如何从以下代码静态初始化my_collestions?我将有5个系列,每个系列都有不同的数字增益,例如: // 2 [buff], [buff] // 3 [buff], [buff], [buff] struct Buff { int len; const char *ptr; } struct Collection { int num; Buff buffers[]; // length is unknown here } static cons

如何从以下代码静态初始化my_collestions?我将有5个系列,每个系列都有不同的数字增益,例如:

// 2 [buff], [buff]
// 3 [buff], [buff], [buff]


struct Buff
{
    int len;
    const char *ptr;
}

struct Collection
{
    int num;
    Buff buffers[];   // length is unknown here
}


static const Collection my_collestions[]; // i need to initialize this

使用向量而不是数组

正如您所定义的,SizeOffCollection不包括数组的空间,因为您没有提供任何长度,就好像数组是空的一样。因此,如果您想分配集合项,您应该自己分配空间,计算所需的正确大小

这意味着不可能创建集合数组,因为对象将没有为其缓冲区保留的空间

中间解决方案是使用指针而不是数组:

struct Collection {
  int num;
  Buff *buffers;
};

在这种情况下,可以在构造函数中分配缓冲区。

可能是这样的吗? 是的:这利用了未定义行为的黑魔法。 然而:好吧,这是在提问时静态地做这件事的唯一方法。 问:这是一个好主意还是应该采取不同的做法? A:这要视情况而定

  struct Buff {
    int         len;
    char const *ptr;
  };

  struct Collection {
    int  num;
    Buff buffers[1];
  };

  template <unsigned S>
  struct CollectionSize : public Collection {
  private:
    Buff extraspace[t-1];
  };

  static const Collection &my_collestions[] = {
    CollectionSize<1>(), // add more constructor arguments so you can initialize the base class. the object is const so this is your last chance to do so.
    CollectionSize<2>(),
    CollectionSize<3>(),
    CollectionSize<4>(),
    CollectionSize<5>()
  };
说明:

诀窍是通过非类型模板在派生类中留出额外的空间,但通过基类数组访问它。你对下一个对象读得太多了,但是内存会在那里,是的,这是一个未定义的行为,但在实践中这会起作用。还可以使数组由常量引用组成,而不是对象本身或指针。您需要引用或指针,以便对象可以切片到它们的基类,因为数组需要是同构类型的。这是非常重要的,因为这是一个引用,而不是其他的,因为C++标准对临时对象的const引用有特殊规则,也就是说,只要引用周围,它们就一直在附近,这样就避免了调用新来动态分配CopySnsig对象。 主要组成部分概述:

const references引用的未命名临时对象const references仍然是有效的对象,仍然是已分配的,只要引用在作用域内,析构函数就不会被调用。在这种情况下,静态引用在作用域内,直到程序作为无法写入的const对象退出。 使对象成为派生模板类型意味着您可以在对象内部分配更多空间供基类使用,这是标准中未定义的,但实际上适用于所有编译器AFAIK。 由于没有虚拟指针的单个继承类的编译器定义的对象布局在实践中有些标准,因此已知派生类的内存直接位于派生类的最后一个成员数组之后。标准中没有定义访问此内存,但在实践中可以使用。 编辑: 我收到了一些关于这个答案的批评,所以我将发表一些额外的评论来解决这个问题 我在回答这个问题之前说,它可能涉及到未定义的内容,但在实践中却相当不错。编译器就是这样做的!因此,实际上,我们只需要担心两件事:

对象布局,并确保有足够的内存供阵列访问。虽然在C++中没有定义对象布局,编译器供应商做的很好,使它已知,并且它是一致的,至少对于没有虚拟指针的类的继承是如此。 成员将按顺序排列。 派生类将位于基类之后的内存中。 因此,即使有填充,也不重要,因为在对象的末尾至少需要有这么多的空间,并且可以通过基类以一致的方式对其进行操作。 C++中的规则,当你访问内存时,你会发生什么。这种数组技巧在C中非常常见。通常它采用简单结构的形式,数组作为大小为0或1元素的最后一个成员,程序员调用malloc以获得更大的大小,然后通过结构的数组访问非端内存。 在实际的实现和我自己的经验中,我从来没有遇到过任何一种情况,其中任何一种都不符合预期。这是程序员的最佳选择吗?。。很可能不是,但这要视情况而定。也许STL向量,甚至是指针的额外间接层,在一些随机的低端系统上都不是一个选项。也许为了优雅的代码,这些对象确实需要在一个数组中


在任何情况下,问题的提出方式是如何静态初始化这些结构,而不是天气,这是一个好主意。这是最好的解决办法。不过,当然也欢迎其他更好的解决方案。

您应该向集合中添加一个构造函数,将缓冲区的数量作为参数,然后在构造函数中初始化缓冲区。@Steger我不需要对该结构进行任何更改,因此我不希望该结构在运行时自行构造。但是您需要可变数量的缓冲区,正当所以你可以定义
一个用于收集或创建围绕集合的模板的构造函数。灵活的数组成员是无效的C++,有没有使用向量的原因?谢谢。我在非标准布局对象中也有同样的想法,您无法保证编译器将如何布局对象。