1

In this answer the user reports that his g++ version compiles VLAs, as well as in this question. On my compiler this also works (has that extension), but if I want to declare such an array as a class member, such as position and velocity in

class PSO
{
    private:
        static double * data;
        static int len;
        static int dim;
        double position [dim];
        double velocity [dim];

        double get_min();
        double get_max();
        void copy_data(double data *);

//...

it does not compile. What is the reason for this? Why would the compiler extension allow VLA in a main function, but not in the declaration of a class member?

Addendum

I am using gcc 4.8.2

EDIT

I know I should have used std::vector or pointers, but I would like to know why it would compile in a main function and not in a class declaration.

EDIT 2

To be clear, this compiles (in my case)

int main()
{
    int size;
    double data [size];

    size = 5;

    return 0;
}

This is not exactly the same as in the other questions I showed, since I did not have a std::cin >> size statement before the array declaration. Does anyone else have this (quirk) in their compiler?

Community
  • 1
  • 1
Konrad
  • 2,207
  • 4
  • 20
  • 31

5 Answers5

4

VLAs (variable length arrays) are a feature added to the C language in the 1999 ISO C standard (and made optional by the 2011 standard). The C++ standard has not adopted them.

VLAs in C++ are a gcc extension. They're closely based on the C version of the same feature. A large part of the reason g++ doesn't permit VLAs as class members is that C doesn't have classes. It does have structures, which are very similar to classes, but C doesn't permit VLAs in structures.

Implementing VLAs as objects with automatic storage duration (non-static local variables) is relatively straightforward. The length of the array is determined by evaluating the expression between the [ and ] when the declaration is encountered, and that determines how much space must be allocated (typically on the stack). Deallocating a VLA is typically done as part of tearing down the stack frame on leaving the block in which the object is declared.

A VLA as a member of a class or structure would be more complicated. In your example:

class PSO {
    ...
    static int dim;
    double position [dim];
    double velocity [dim];
};

the position and velocity members would have to be allocated each time a PSO object is created, using the current value of dim to determine the length. If dim has not had a value assigned to it, it's going to be 0 -- and neither C nor C++ permits zero-length arrays. If a value has been assigned, then the offset of velocity will have to be computed at run time; that's not impossible, but normally members of classes and unions have constant offsets. Presumably the length of position and velocity would be determined by the value of dim when the PSO object is created -- but dim can be modified later, making it difficult to determine the length of the arrays for an arbitrary PS0 object.

Applying sizeof to a VLA object computes the size at run time. That size is typically stored in a compiler-created object associated with the type of the VLA. Each defined VLA object has its own type. If VLAs are permitted as class members, the number of distinct sizes can be arbitrary, as multiple PS0 objects are created dynamically.

None of these difficulties are insurmountable. Ada, for example, permits records (similar to C and C++ structures) with members that are arrays whose length can vary for each instance of the record type:

type Rec(Length: Natural) is
    record
        S: String(1 .. Length);
    end record;

Supporting this as a language extension in C++ would require a great deal of work in the compiler. Presumably the gcc team, since they had to implement VLAs for C, decided that implementing them similarly for C++ would have a decent payoff without too much effort. Extending them as you suggest would have required considerable work (not least designing the semantics so they can be used consistently) for what they probably did not consider to be sufficient benefit -- especially since C++ has much more powerful features in the standard library container classes.

gcc's support for variable length arrays is described here, or type "info gcc" and search for "Arrays of Variable Length".

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
3

So, let's first make something clear. Variable Length Arrays in C++ is a compiler extension. This isn't directly supported via the C++ standards.

So, there are two different kinds of VLAs that are being talked about here. Stack allocations, and last struct member allocations. Let's deal with them one at a time.

Stack Allocations

Here, we're simply talking about something like:

int main() {
    int length = 12;
    float array[length];
}

This is fairly straightforward. We have a pointer to the end of the stack space that we are currently using, and we extend that when we get to the array declaration.

Struct Allocations

This is more complicated. The normal compiler extension that is supported allows for the last member to be a variable length array. But we can only do this in one way:

struct MyObject {
    int x;
    float y;
    double z[]; // Note that we didn't give this any length!
};

Now. What is the size via sizeof() of this object? It's probably 8. This size allocates no space for the array z. It assumes that it is length 0. So what can we do with this?

struct MyObject *object = malloc(sizeof(MyObject) + 8*sizeof(double));

This allows us to access 8 doubles via the object->z array.

Now, why couldn't we do other things?

Given enough compiler extensions we could do more things. But the issue is that in general, we want to do at most do a pointer plus a couple (but fixed number) of computed offsets to every variable in the system. These two extensions don't break that desire.

How about the code you suggested?

Allowing things like this:

struct MyOtherObject {
    int dim;
    int x[dim];
    int y[dim];
};

Could work. But, it is a more complicated extension. And it's not included. There's some concerns with it, like having the ability to change dim after the allocation has occurred. But in the end, those problems could be dealt with.

But that code is just not accepted by the compiler extension, because it is outside of the specification that defines it.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • Yes, good answer. But why would that `main` function compile in my case? I also could not get why it compiles, since `size` is indeed undefined when I declare `data`, but it does compile. Perhaps a bug in my compiler? – Konrad Apr 22 '15 at 00:14
  • So, to clarify: You mean that the compiler needs to allocate a certain size for a class/struct when I declare it (and for when I eventually instantiate it), but having a VLA in the definition of the class would complicate that allocation of that size? I understand that in the `main` function it's simpler, it just allocates more space on the stack, while in the case of a class/struct things are less clear. – Konrad Apr 22 '15 at 00:17
  • 1
    @KonradKapp: There's some unspecified value in `size`. I suspect that the system is just using that unspecified value. But either way, I imagine that is just considered undefined behavior by the compiler. – Bill Lynch Apr 22 '15 at 00:20
  • 1
    @KonradKapp: Having the variable length members becomes extra complicated when you think about cases like multiple and virtual inheritance. The last member VLA that I talk about above just reports a compiler error in those cases. – Bill Lynch Apr 22 '15 at 00:24
  • @BillLynch ah yes I never thought of that, that `size` will have some random number in it after declaration. Puzzles me even more then why the compilation is allowed, since it can allocate to `data` some insane sizes then. All the more reason to compile with -Wall. – Konrad Apr 22 '15 at 00:30
1

It's quite easy to create local VLA using alloca/just modifying stack pointer. There are many challenges in supporting it in a type (breaking offsets/pointers to members, etc.). Allocating this as part of the object would make it's size dynamic - making things like assignment and pointer arithmetics more complicated. Since we can use pointers to data outside the object, it just doesn't seem like it's worth to support it for types.

yachoor
  • 929
  • 1
  • 8
  • 18
0

This is absolutely a guess, and I've primarily been programming in C lately. Perhaps it's because classes and structs need to have a standard size in bytes, so that they can be stored linearly in memory at fixed intervals while also being traversable by code that uses sizeof. If they allowed VLA, then one object might have a 16 byte array, and another might have a 16000 byte array. And then how does the compiler make code to traverse the different length objects? My guess: it just calls that an error and doesn't bother.

I'm sure you could get around this by using malloc and pointers.

0

When you don't know the length of an array until runtime, you should use pointers. In your example, this would be done like the following:

class PSO
{
    private:
        static double * data;
        static int len;
        static int dim;
        double* position;
        double* velocity;

        double get_min();
        double get_max();
        void copy_data(double data *);

    //...
}

You would then instantiate the pointers somewhere in your code (such as the constructor of PSO) like this:

position = new double[dim];
velocity = new double[dim];

Remember that you can't define variables in your class definition, only declare them.

Don't forget -- since you are writing in C++, you also have access to other structures such as vector, which can hold variables in dynamically sized arrays.

  • 1
    This doesn't answer the question. It's a reasonable workaround to not being able to define a variable length array in the class, but the question was *why* that's not permitted. – Keith Thompson Apr 21 '15 at 23:49
  • Because it can't be known until runtime. An array has preallocated memory; if you don't know how much data you have, you have to allocate memory yourself at runtime. – The name's Bob. MS Bob. Apr 21 '15 at 23:50
  • @KonradKapp I gave an explanation. Remember, you can't define variables in a class definition. Also, dim is undefined; it wouldn't make sense as you're asking. – The name's Bob. MS Bob. Apr 21 '15 at 23:55
  • 1
    I think you're glossing over a step. Why couldn't you *declare* a VLA in a class? – Keith Thompson Apr 21 '15 at 23:59
  • @KeithThompson dim is undefined. VLAs need a length. – The name's Bob. MS Bob. Apr 22 '15 at 00:01
  • 1
    `dim` is static. In principle, it could be assigned a value before any `PSO` objects are created, and that value used to determine the length of the array. I'm not saying it would be a great idea, but it's not inconceivable -- and VLAs are a language extension anyway. – Keith Thompson Apr 22 '15 at 00:06
  • @dr_andonuts but the code in edit 2 compiles (in the question, `main` function). `dim` is also undefined in that declaration of the `data` array. So, once again...why does the one in `main` compile, but not the one in the class declaration? – Konrad Apr 22 '15 at 00:06
  • @KeithThompson It could be assigned a value w/o a `PSO` object...as a private class variable? How? Unless there's a static function specifically for that. – The name's Bob. MS Bob. Apr 22 '15 at 00:08