Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable-sized objects on the stack

I can create a variable-sized C-style array on the stack with no problems:

void f(int n) {
  float data1[n]; // OK
}

But I can't do the same with std::array:

void f(int n) {
  std::array<float,n> data2; // error: ‘n’ is not a constant expression
}

The following example illustrates my point more thoroughly:

#include <array>
#include <cstdio>

template<int N>
class A{
  public:
    void print() { 
      printf("data[0]: %2.2f\n", data[0]);
    }
  private:
    float data[N];
};

void f(int n) {
  float data1[n]; // OK
  std::array<float,n> data2; // error: ‘n’ is not a constant expression
  A<n> data3; // error: ‘n’ is not a constant expression
}

int main(int argc, char **argv) {
  f(3);
}

My Questions: Is there a way to create a variable-sized class/struct strictly on the stack? If so, how? If not, is this due simply to the specifications or is there an underlying technical reason that it is forbidden?

like image 571
Jake Avatar asked Jul 25 '26 18:07

Jake


2 Answers

You are comparing apples with oranges.

When you use a variable-length array you refer to a feature that comes from older days (introduced in C99) that allows specifically to allocate arrays on the stack without knowing the size at compile time. This is done by the compiler by just reserving the required stack size at runtime instead that precompute the displacement before.

If I remember correctly it has actually been relegated in C++11 to a status of optional feature (while C11 brought it along).

Then you have std::array<T,size_t> which is something completely different. It's a template and it is required to be instantiated with compile time types / values. So you simply can't do what you want.

The main point is that C++ is a language which allows you to avoid the need of VLA, since you have std::vector and dynamic allocation.

If you really want to allocate things on stack you must look for specific and dirty tricks which aren't needed 99.9% of the time like placement new and alloca (which is non standard in any case), eg:

void *reserved = alloca(sizeof(MyClass));
new (reserved) MyClass();
like image 157
Jack Avatar answered Jul 28 '26 07:07

Jack


Is there a way to create a variable-sized class/struct strictly on the stack?

No. There is no support for variable-sized class/struct in the C++ Standard, so they can't be created anywhere. That said, you can create a class/struct in which the final data member is an array, and deliberately overrun the array dimensions. This trick's known as the "struct hack" in C - see the FAQ. Whether it's undefined behaviour depends on your implementation. You can use it in combination with alloca and placement-new to create such a variable on the stack, but should be careful to manually delete it afterwards if your program depends on any side-effects of the destructor.

If not, is this due simply to the specifications or is there an underlying technical reason that it is forbidden?

The reason is performance. Normally, variables on the stack can be accessed using the stack pointer CPU register plus a constant offset, which the compiler can calculate for any given local/automatic variable at compiler time. When you have variable length content on the stack, the local variables after that are no longer at fixed offsets from the stack pointer register, which means the compiler has to generate code to add various values in order to calculate a runtime offset at which to access the variables. When you have several variable-length stack-hosted variables, the problems compound and the performance degrades further. To avoid programmers producing unexpectedly slow code, and to keep compilers simpler, the Standard doesn't require support for variable length types.

like image 41
Tony Delroy Avatar answered Jul 28 '26 07:07

Tony Delroy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!