灵活的数组成员在C++中是否有效?

MSN*_*MSN 36 c++ flexible-array-member

在C99中,您可以声明结构的灵活数组成员:

struct blah
{
    int foo[];
};
Run Code Online (Sandbox Code Playgroud)

但是,当有人在这里工作时尝试使用C++中的clang编译一些代码时,该语法不起作用.(它一直在与MSVC合作.)我们不得不将其转换为:

struct blah
{
    int foo[0];
};
Run Code Online (Sandbox Code Playgroud)

通过C++标准,我发现根本没有提到灵活的成员数组; 我一直认为这[0]是一个无效的声明,但显然对于一个灵活的成员数组它是有效的.灵活的成员数组在C++中实际上是否有效?如果是这样,是正确的声明[]还是[0]

Mar*_*wis 26

C++最初是在1998年标准化的,所以它早于将灵活的数组成员添加到C(这在C99中是新的).2003年对C++有一个更正,但没有添加任何相关的新功能.C++的下一个版本(C++ 0x)仍在开发中,似乎没有添加灵活的数组成员.

  • 你能否更新这个答案?似乎C++ 11没有添加灵活的数组成员(§9.2/ 9),看起来C++ 14将是相同的. (12认同)
  • 而且C++ 17也没有它们,但我认为它们仍然在被研究,所以也许C++ 2a? (5认同)
  • 有什么办法可以使GCC`g ++`发出警告?-std = c ++ xx -Wall -Wextra是不够的。害怕 :-( (3认同)
  • 尽管确实存在一篇论文,但 C++20 中仍然没有任何内容:https://thephd.github.io/vendor/future_cxx/papers/d1039.html (3认同)
  • @CiroSantilli新疆改造中心六四事件法轮功如果我没记错的话`-Wpedantic`或`-pedantic`会触发警告。 (2认同)

Mic*_*urr 19

C++不支持结构末尾的C99灵活数组成员,使用空索引表示法或0索引表示法(禁止特定于供应商的扩展):

struct blah
{
    int count;
    int foo[];  // not valid C++
};

struct blah
{
    int count;
    int foo[0]; // also not valid C++
};
Run Code Online (Sandbox Code Playgroud)

据我所知,C++ 0x也不会添加这个.

但是,如果将数组的大小设置为1个元素:

struct blah
{
    int count;
    int foo[1];
};
Run Code Online (Sandbox Code Playgroud)

事情是有效的,并且工作得很好.您可以使用不太可能具有逐个错误的表达式来分配适当的内存:

struct blah* p = (struct blah*) malloc( offsetof(struct blah, foo[desired_number_of_elements]);
if (p) {
    p->count = desired_number_of_elements;

    // initialize your p->foo[] array however appropriate - it has `count`
    // elements (indexable from 0 to count-1)
}
Run Code Online (Sandbox Code Playgroud)

因此它可以在C90,C99和C++之间移植,并且与C99的灵活阵列成员一样.

Raymond Chen对此做了一个很好的写作:为什么有些结构以1的数组结束?

注意:在Raymond Chen的文章中,初始化"灵活"数组的示例中存在一个错字/错误.它应该是:

for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
  TokenGroups->Groups[Index] = ...;
}
Run Code Online (Sandbox Code Playgroud)

  • 但是,即使您分配了多余的内存,您仍然无法有效地访问一个元素的数组边界之外的成员.行为未定义; C++实现将在其权限范围内根据构造的对象的实际类型添加边界检查. (7认同)
  • 好吧,我想我必须吃掉我的话.除了WG14以外,没有人声明这是UB(缺陷报告51:http://www.open-std.org/Jtc1/sc22/wg14/www/docs/dr_051.html).然而,我认为1)WG14在DR51中提出的"更安全的成语"是完全荒谬的,2)UB在所有对我来说都很重要的平台上表现如预期,3)替代方案(也不是UB) )不太方便和/或更容易使用(因此更容易导致可观察到的错误) - 所以我可能会继续使用它.但现在至少我会知道我违反了规则...... (7认同)
  • 是的,我没有声称它不是一种有用的技术,只是它没有严格遵守.不幸的是,出于不同的原因,更安全的习语也是UB.您只能对实际存在的对象执行指针运算,并且只有在分配了足够对齐和_size_的内存后,POD对象才会开始存在.如果使用非常大的数组声明某些内容并且您没有为它分配足够的空间,则它无法开始存在. (4认同)
  • @Michael:我认为Charles说***元素的原因不是因为他认为分配数组是不可能的,而是因为1是你特定结构中数组的长度.声称是因为`p-> foo`的类型是'blah [1]`,那么`p-> foo [1]`就是UB.但是,虽然`p-> foo [1]`在`foo`对象之外,但它不在`char`数组之外,而是用`malloc`分配的,所以它*是*在一个对象里面.通过`char*`读取访问适当的强制转换,至少会没问题.我不记得法律标准如何失败了. (3认同)
  • @Charles - 我不认为你是对的(甚至是迂腐),否则以下是未定义的行为:`int*p = malloc(sizeof(int)*4); p [3] = 0;`. (2认同)
  • 另外,(再次仅谈论语言律师的好奇心)我也不相信您的“offsetof”调用严格符合要求,因为“foo[desired_number_of_elements]”不指定假设的静态“blah”对象的成员。我认为你必须执行“offsetof(blah, foo) +desired_number_of_elements”。 (2认同)

jxh*_*jxh 5

如果您可以将应用程序限制为仅需要几个已知大小,那么您可以使用模板有效地实现灵活的数组。

template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
    T flex_[SZ];
};
Run Code Online (Sandbox Code Playgroud)

  • 固定和灵活的声音对我来说很矛盾。 (2认同)