1

I compiled and ran the following C++ code, blindly trying to create a flexible array member like you can in C:

#include <iostream>

template <typename T>
struct Vector {
    int length;
    T ts[];
};

Vector<int> ts = {
    3,
    {10, 10, 10},
};


int main() {
    std::cout << sizeof(ts) << std::endl;
    std::cout << ts.data[1] << std::endl;
    return 0;
}

The code compiles and runs just fine, and gives the same output that C would in the same circumstance (it outputs 4 and then 10).

Now, according to this answer from 2010 what I have written should not be valid C++. Furthermore, according to this wikipedia article, "C++ does not have flexible array members".

My question is, which C++ feature am I actually using in the above code, specifically on the line that says "T ts[];"? Does that code actually do what I think it does in general, or is it undefined behavior?

jcarpenter2
  • 5,312
  • 4
  • 22
  • 49
  • 1
    It's just a non standard extension. The language specification itself does not have them but gcc's implementation does. – Paul Rooney Sep 08 '17 at 03:31
  • Compiler extension, most likely. What tool chain are you using? – user4581301 Sep 08 '17 at 03:31
  • I am not sure if you can determine if behavior is defined or not for ill-formed c++ program. It should not compile according to standard, and if it does for some compiler extention, you cannot rely on standard anymore. – Slava Sep 08 '17 at 03:31
  • @user4581301 I am using mingw currently. – jcarpenter2 Sep 08 '17 at 03:32
  • 1
    Add the -pedantic compiler option and you'll get a warning, but otherwise it lets it pass. Same thing with Variable Length Arrays. – user4581301 Sep 08 '17 at 03:39

1 Answers1

2

It is one of those things which are different between C and C++. A flexible array member is valid in C but not C++.

That said, many modern compilers compile C as a subset of C++, taking care to care only when you torque up the compiler error diagnostics.

David Tribble spends a moment on it at his Incompatibilities Between ISO C and ISO C++ page, where he specifically addresses this issue:

C++ does not support flexible array members.

(This feature might be provided as an extension by some C++ compilers, but would probably be valid only for POD structure types.)

So yes, this is undefined behavior. The correct way (in both C and C++) to write such a thing is to give it a non-zero dimension:

template <typename T>
struct Vector {
    int length;
    T ts[1];
};

You have another issue: you must allocate memory for said object. Simply specifying an initializer is not enough. As far as every access to such a thing exists, the compiler only ever thinks it is its minimal size.

This “range hack” is so called because the programmer explicitly uses/abuses C's (and C++'s) ability to violate range bounds to do something tricky.

The consequences of this are many, including inability to store these things in any standard container, or pass them around by value, or do most anything that eschews handling it through a pointer. It has its place, but for the vast majority of use cases C++ has superior options.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39