3

When allocating on the stack, I don't necessarily need to know the size of a C array being allocated at compile time. i.e. I can do this:

void foo(size_t s) {
    uint8_t bar[s]; // `s` not known at compile time
    some_func_that_uses_bar(bar, sizeof(bar));
}

However, to be less error-prone, it feels I should be able to do this with C++ std::arrays as well, yet I haven't been able to figure out how (nor whether it's even possible).

Peter Jankuliak
  • 3,464
  • 1
  • 29
  • 40
  • 2
    The size of the array in [`std::array`](https://en.cppreference.com/w/cpp/container/array) is a template argument. And templates are a compile-time only thing. What you seem to need is a [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) instead (especially considering that [variable-length arrays](https://en.wikipedia.org/wiki/Variable-length_array) are not really a part of C++). – Some programmer dude Aug 02 '19 at 08:48
  • 4
    Also worth to note that such dynamic array allocation as in your example is standardized only in C, in C++ although supported by some compilers it is non-standard. – sklott Aug 02 '19 at 08:49
  • 4
    Contrary to popular belief, allocating large arrays on the stack reduces performance because the top of the stack is moved out of the hot region. – rustyx Aug 02 '19 at 08:52
  • Do you know the maximum value of `s`? If so (and if you are really hellbent on keeping it on the stack) you could always use this maximum value as array size. And if you don't know the maximum value, how can you be sure that you won't get a stack overflow? – Max Langhof Aug 02 '19 at 09:01
  • See also [std::vector versus std::array in C++](https://stackoverflow.com/questions/4424579/stdvector-versus-stdarray-in-c). – Raedwald Aug 02 '19 at 09:08

3 Answers3

6

No, you can't. C has added special support for variable-length arrays, but C++ has not. You can get a similar effect using alloca(), but that's not a standard function and will require additional work if you're using it with a class requiring a specific alignment, and requires you to manually invoke the constructors and destructors.

For that use case, a normal C++ programmer would use std::vector.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • Thanks. Re: "a normal C++ programmer would use std::vector", the buffers I'm allocating are quite small, the alternative I think I'll prefer is to use the C type array allocation together with std::string_view. – Peter Jankuliak Aug 02 '19 at 09:44
  • For quite small buffers, a normal C++ programmer would use `std::vector`. A really *good* one might use a profiler to determine whether the performance hit from that heap allocation was unacceptably impacting the real-world performance. A bad one would assume it was unacceptable, without actually profiling. – Sneftel Aug 02 '19 at 09:47
  • 1
    Why use non standard alloca, when one could use non standard VLA just as well? – eerorika Aug 02 '19 at 09:50
  • Profiling is on the table. My "educated guess" tells me that for small arrays allocating on the stack is faster, thus I don't see why a normal programmer wouldn't start there. – Peter Jankuliak Aug 02 '19 at 09:54
  • @PeterJankuliak Because it makes the code less elegant and harder to follow. It makes debugging more difficult, and makes crashes harder to diagnose. And while stack allocation is sometimes faster than heap allocation, you are almost certainly wrong if you think this allocation is going to significantly impact the performance of the code. – Sneftel Aug 02 '19 at 09:57
1

If you want to allocate array in stack you can use Smallvector from llvm. for small size it starts from stack and then if needed with push_back it goes to heap memory:

llvm::SmallVector<int, 5> smallVector;
for(int i = 0; i < 5; i++) { 
    smallVector.push_back(i); 
} // No heap allocations have been performed up to this point.
smallVector.push_back(6); // heap allocation now
Oblivion
  • 7,176
  • 2
  • 14
  • 33
0

i.e. I can do this:

void foo(size_t s) {
    uint8_t bar[s]; // `s` not known at compile time
    some_func_that_uses_bar(bar, sizeof(bar));
}

No, you cannot do this in C++. The size of an array must be a compile time constant.

it feels I should be able to do this with C++ std::arrays as well

No, this is not possible using std::array either.

If the size of the array is not known at compile time, you must allocate it dynamically. Typical solution is to use a vector.

If you expect the size to be small, a possible optimisation is to use a custom vector type that uses a small buffer optimisation to avoid dynamic allocation when the size does not exceed a compile time defined limit.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326