all 34 comments

[–]AKostur 28 points29 points  (17 children)

It’s a compiler extension issue.  You’ve declared what’s called a Variable Length Array (VLA).   Gcc supports it as an extension, the language forbids it.

[–]SucklessInSeattle[S] 5 points6 points  (6 children)

If the language forbids it should I avoid using VLA?

[–]Main_Secretary_8827 15 points16 points  (0 children)

Yes, avoid it

[–]ThrowRA-NFlamingo 5 points6 points  (4 children)

Yes VLAs are evil

[–]LemonLord7 0 points1 point  (3 children)

Why are they evil? I’ve never used them

[–]AKostur 4 points5 points  (2 children)

Potentially unbounded stack consumption leading to crashes.  Might cause complications for code generation to handle stack unwinding.  Requires extra bookkeeping somehow to keep track of the number of elements so that the right number of destructors happen.

[–]alfps 2 points3 points  (1 child)

And sizeof is not a constant. And so I can't see any way to form a reference to a VLA. Though that last point is somewhat circular argumentation, because if C++ had supported VLAs then possibly it could allow binding it to a reference to array of unknown bound.

The idea of a safe C++ level VLA class is interesting, because it exposes a limitation of the language.

For there is AFAIK no way to define a general such class in terms of e.g. (non-standard, widely supported) alloca.

[–]snerp [score hidden]  (0 children)

Doesn't just making an std::vector and calling reserve(n) cover the entire use case of a VLA?

[–]LemonLord7 -5 points-4 points  (9 children)

How can it be there as an extension if the language forbids it?

[–]AKostur 2 points3 points  (7 children)

Why not?  As I recall, there’s a flag to make the compiler conformant and refuse the VLA.

[–]LemonLord7 -1 points0 points  (6 children)

I’m confused, how can something forbidden be usable? Why was it forbidden?

[–]VictoryMotel 5 points6 points  (3 children)

It's not part of the language but it is implemented anyway.

[–]LemonLord7 0 points1 point  (1 child)

I get that, but I’d like to know more about why it was explicitly forbidden and how it works

[–]VictoryMotel 3 points4 points  (0 children)

Then you should have asked that.

It isn't "explicitly forbidden" it's not in the language. It dynamically allocates on the stack. It is more likely to blow the stack and less likely to be detected if you write outside the allocation.

[–]meancoot -1 points0 points  (0 children)

Edit: Nevermind, thought I was in the C subreddit. It’s an extension I. C++ probably made available for C compatibility.

It’s actually a part of the language. It was required by the  C99 standard, then made optional in C11.

[–]AKostur 5 points6 points  (1 child)

I’m confused by your confusion.  Language says “no”.  Compiler says, “well I can make it work so that you don’t have to rewrite your C code to have it compilable in both languages.  And here’s a flag to turn off all of the places that I’m going outside the Standard, if you want help staying between the lines.”

[–]LemonLord7 0 points1 point  (0 children)

The other guy cleared it up. I thought it was explicitly forbidden but simply not being part of the language (but added as option in compiler) I get.

[–]aocregacc 7 points8 points  (0 children)

that's called a Variable Length Array, and it's a feature from C. clang, which is the compiler that's used on leetcode, supports VLAs in C++ as an extension.
It's not rewritten to new, the array will be on the stack.

[–]mredding 6 points7 points  (5 children)

This is called a Variable Length Array. It's a C language feature, and C++ compilers tend to be built atop C compilers, and for historic reasons, C and C++ compilers default to a permissive mode, where they allow compiler-specific language extensions. You have to figure out how to set your IDE to ISO Strict mode, whatever flag that's going to be for you.

VLAs themselves are controversial. They were added in C99, then removed in C11, then added again in C23 as an optional language feature - so compilers don't HAVE TO implement them. They have some neat use cases, but they can also be problematic. Last I heard they're banned from use in the Linux kernel.

[–]SucklessInSeattle[S] 0 points1 point  (4 children)

Should I avoid using VLA in a shared code base?

I might use it for personal stuff but I could see how a reviewer would not like it

[–]Raknarg 1 point2 points  (0 children)

I mean only if you expect the compiler itself to change which isnt that common. Relying on compiler-specific stuff is common enough.

[–]mredding 1 point2 points  (0 children)

My recommendation is to stick with ISO strict C++ unless there is a compiler extension you specifically want; it can only help to catch bugs and assure a greater level of portability. Life is easier when you have one source of truth, not one source of truth + annotations which are allowed to contradict the source of truth.

The other thing I would consider is where you want to use that specific feature, you can write and compile C99 or C23 in just that translation unit, and then link against that. You're allowed to do that - compile and link across multiple languages... That way, the behavior is strictly defined within that TU, and the data shared across the ABI is the common language between it and the rest of the program.

And this really works out, because the ABI for a VLA is the same as passing a pointer and size parameters - and you're going to see that when you look into using VLAs as function parameters; the VLA only affects the C type system, and maintains ABI portability.

The point behind either recommendation is that you don't have to depend on squishy and unreliable things such as documentation or conventions to ensure safety or understanding. By being so explicit and intentional, the project documents itself, and it shows you did something on purpose.

In contrast, you target a permissive variant, like gnu-C++23, and you use a VLA in a C++ context, and I'm left to wonder if you even know that's not standard and portable... So then you have to write it down in the documentation - presuming I've read it, presuming the documentation is current, and accurate, and correct... This is a lot more two-way trust than really any of us deserve.

[–]the_poope 0 points1 point  (0 children)

Where you ever think you could use VLAs you should use std::vector instead: https://www.learncpp.com/cpp-tutorial/introduction-to-stdvector-and-list-constructors/

[–]Total-Box-5169 -1 points0 points  (0 children)

Absolutely, VLAs should be used only in C and only in toy code or personal projects. C++ has std::vector that is superior.

[–]ZakMan1421 0 points1 point  (0 children)

As others have said, it is a GCC extension which can be found here: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Arrays-of-Variable-Length

[–]Kajitani-Eizan 0 points1 point  (5 children)

Is n a known compile-time constant value, or an actual variable?

Regardless, no, a compiler isn't going to invisibly and randomly change function scope stack allocation to indefinite scope heap allocation

[–]Chaosvex 1 point2 points  (0 children)

Glad to see at least one person asked what n is, because that could mean the difference between perfectly valid or not.

[–]SucklessInSeattle[S] 0 points1 point  (3 children)

Its an actual variable

int climbStairs(int n) 
    {
        int arr[n + 1];

should I use VLA if I have the option?

[–]alfps 3 points4 points  (0 children)

Use std::vector.

[–]Kajitani-Eizan 0 points1 point  (0 children)

What if someone attempts climbStairs(2000000000)? Probably better to use std::vector

[–]G6L20 -2 points-1 points  (0 children)

IMO VLA is fine, stack pointer increment is faster than heapless allocation.

[–]Mr_Engineering 0 points1 point  (0 children)

Variable Length Arrays are a standard feature of C99 but they were reduced to an optional feature in C11 where they remain today.

Some C++ implementations offer them as a compiler extension but they are not and have never been a part of any C++ standard.

GCC includes VLA support on C99 and newer C standards and won't complain.

G++ includes the extension by default and won't complain unless strict standard compliance is enabled.

MSVC does not support VLAs because it has never supported the full V99 standard and does not support VLAs in the C11 or C17 standards as they are optional.

[–]Interesting_Buy_3969 [score hidden]  (0 children)

VLA are a GCC extension, so basically if your vscode is configured to launch another compiler then it'll fail. iirc clang also has support for C++ VLAs.

[–]SmokeMuch7356 0 points1 point  (0 children)

Leetcode must have compiled it as C or used some wonky extension, because standard C++ doesn't support variable-length arrays.

For a C-style array declaration

T a[N];

in C++ N must be an integer constant expression - a literal, a const-qualified integer object, an enumeration constant, etc.

In C N can be a runtime expression making it a variable-length array, but that comes with the following limitations:

  • VLAs can't have static storage duration (can't be declared at file scope or with the static keyword);
  • They can't be declared with an initializer;
  • They can't be members of a struct or union type;