Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this definition of an array legal?

49 views
Skip to first unread message

Paul

unread,
Feb 1, 2017, 9:09:58 PM2/1/17
to
Is the below code legal? On the one hand, the array length seems constant
as required. On the other hand, I read that a non-reference const as a
function parameter is the same type as a non-const. For example you can't
overload void f(const int); with void f(int);
Thanks for letting me know.

Paul
// CODE BELOW
void makeArray(const int K)
{
int a[K];
}

karolak kolo

unread,
Feb 1, 2017, 9:18:34 PM2/1/17
to
Unfortunately it isn't possible by declaring an array this way. Even though the argument is constant, the argument used when actually calling the function may not be constant anymore. Also, the array will stop existing as soon as the function ends because it is local, not global.

You can do it an other way though, using operator new, and defining the arrat globally.

int* globalArray;

void makeArray(int n)
{
delete[] globalArray;
globalArray = new int [n];
}

You have to be careful with this though. You probably want to read more about the operator new[], delete[] and pointers.

Alf P. Steinbach

unread,
Feb 1, 2017, 9:30:49 PM2/1/17
to
The `K` here is not known at compile time (and context isn't considered:
it doesn't matter if there is only one one call of `makeArray` and that
call has a literal value as argument). And so in standard C++ this is
not valid code. In standard C++ the size of an array variable must be
compile time constant.

However, in C99 the above is valid. There it's a variable length array,
called a VLA. For variadic arrays `sizeof` is evaluated at run-time.

The g++ compiler supports C99 VLAs as a language extension. To avoid
having non-portable code like that silently accepted you can use the
option `-pedantic`, which produces warnings about such constructs, but
still let the compiler produce an executable. I prefer to have these
warnings treated as errors, via `-pedantic-errors`.

In Windows' command interpreter `cmd.exe`, where `doskey` is used to
define an alias with relevant options:


[example]
[C:\my\temp]
> doskey g++=g++ -std=c++14 -Wall -Wextra -fexec-charset=cp1252 $*

[C:\my\temp]
> type foo.cpp
void makeArray(const int K)
{
int a[K];
}

auto main() -> int {}

[C:\my\temp]
> g++ foo.cpp
foo.cpp: In function 'void makeArray(int)':
foo.cpp:3:9: warning: unused variable 'a' [-Wunused-variable]
int a[K];
^

[C:\my\temp]
> g++ foo.cpp -pedantic
foo.cpp: In function 'void makeArray(int)':
foo.cpp:3:12: warning: ISO C++ forbids variable length array 'a' [-Wvla]
int a[K];
^
foo.cpp:3:9: warning: unused variable 'a' [-Wunused-variable]
int a[K];
^

[C:\my\temp]
> g++ foo.cpp -pedantic-errors
foo.cpp: In function 'void makeArray(int)':
foo.cpp:3:12: error: ISO C++ forbids variable length array 'a' [-Wvla]
int a[K];
^
foo.cpp:3:9: warning: unused variable 'a' [-Wunused-variable]
int a[K];
^

[C:\my\temp]
> _
[/example]


Cheers & hth.,

- Alf

Paavo Helde

unread,
Feb 2, 2017, 1:41:32 AM2/2/17
to
On 2.02.2017 4:18, karolak kolo wrote:
> Unfortunately it isn't possible by declaring an array this way. Even though the argument is constant, the argument used when actually calling the function may not be constant anymore. Also, the array will stop existing as soon as the function ends because it is local, not global.
>
> You can do it an other way though, using operator new, and defining the arrat globally.
>
> int* globalArray;
>
> void makeArray(int n)
> {
> delete[] globalArray;
> globalArray = new int [n];
> }

Please do not advocate mutable globals, uninitialized data or lack of
RAII here! Somebody reading this group might get an idea that this kind
of code is actually acceptable.

> You have to be careful with this though. You probably want to read more about the operator new[], delete[] and pointers.

Why? What's wrong with std::vector?

Everything you need to know about new[] is that whenever you feel
compelled to use it then most probably you are doing something wrong.

Cheers,
Paavo

Scott Lurndal

unread,
Feb 2, 2017, 8:31:44 AM2/2/17
to
Paavo Helde <myfir...@osa.pri.ee> writes:
>On 2.02.2017 4:18, karolak kolo wrote:
>> Unfortunately it isn't possible by declaring an array this way. Even though the argument is constant, the argument used when actually calling the function may not be constant anymore. Also, the array will stop existing as soon as the function ends because it is local, not global.
>>
>> You can do it an other way though, using operator new, and defining the arrat globally.
>>
>> int* globalArray;
>>
>> void makeArray(int n)
>> {
>> delete[] globalArray;
>> globalArray = new int [n];
>> }
>
>Please do not advocate mutable globals, uninitialized data or lack of
>RAII here! Somebody reading this group might get an idea that this kind
>of code is actually acceptable.

It is actually aceeptable.

Paavo Helde

unread,
Feb 2, 2017, 9:54:14 AM2/2/17
to
In a very special situation and extra careful programmers - maybe. But
do you imagine how many bugs the average noob will create when writing
this kind of code?

Cheers
Paavo


Bonita Montero

unread,
Feb 2, 2017, 11:32:54 AM2/2/17
to
Am 02.02.2017 um 03:09 schrieb Paul:

> void makeArray(const int K)
> {
> int a[K];
> }

That's not legal C++-code.

But you can use alloca in C++ to have a variable length array:

#include <malloc.h>

void makeArray( const int K )
{
int *a = (int *)alloca( K * sizeof(int) );
}

With almost any copiler you lose one register which becomes the frame
-pointer because the stack-pointer is advanced a variable distance and
the compiler would not be able to find back to the calling stack-frame
without this frme-pointer.

--
http://facebook.com/bonita.montero/

Scott Lurndal

unread,
Feb 2, 2017, 11:48:12 AM2/2/17
to
I'm not sure the audience here encompasses the "average noob".

I think I'd rather have a programmer who had created such bugs and had
learned to debug them and program correctly to avoid them, rather than a programmer who
lets the language do all the work without understanding how the machine
works, warts and all.

Andrey Tarasevich

unread,
Feb 2, 2017, 12:36:19 PM2/2/17
to
On 2/1/2017 6:09 PM, Paul wrote:
> Is the below code legal?

No.

> On the one hand, the array length seems constant
> as required.

The requirement is for the array size to be an Integral Constant
Expression. A function parameter, even of const type, cannot participate
in an Integral Constant Expression.

--
Best regards,
Andrey Tarasevich

Alf P. Steinbach

unread,
Feb 2, 2017, 2:26:40 PM2/2/17
to
On 02.02.2017 17:32, Bonita Montero wrote:
> Am 02.02.2017 um 03:09 schrieb Paul:
>
>> void makeArray(const int K)
>> {
>> int a[K];
>> }
>
> That's not legal C++-code.
>
> But you can use alloca in C++ to have a variable length array:
>
> #include <malloc.h>
>
> void makeArray( const int K )
> {
> int *a = (int *)alloca( K * sizeof(int) );
> }

Note that

• `alloca` is not standard, but is commonly available, and

• unfortunately how to check for allocation failure, or even if that's
possible at all, differs between compilers/systems.

There have been proposals for variable length arrays in C++, but as far
as I know they've all been discontinued. :( E.g. see <url:
http://stackoverflow.com/a/40656359/464581>.

It's sad because it absolutely needs core language support: one can't
implement a reasonable dynamic length stack based array as a library
solution. One IMO unreasonable way, that in principle could be used for
e.g. string encoding conversions, is to allocate a global buffer that is
treated as a stack and passed down the call chain. This was suggested
seriously in comp.std.c++ when VLA were discussed there, but I have
never seen or heard about that possible technique elsewhere.


> With almost any copiler you lose one register which becomes the frame
> -pointer because the stack-pointer is advanced a variable distance and
> the compiler would not be able to find back to the calling stack-frame
> without this frme-pointer.

In a debug build there's usually a frame pointer regardless of whether
`alloca` is used or not. This allows a debugger to walk up the stack in
order to present the current call chain. A modern processor has enough
registers that I wouldn't worry about any lost optimization opportunity.

The main problem, as I see it, apart from the low level of abstraction,
is for portable code: that because `alloca` isn't standard, there's no
directly portable way to check if it succeeds.

For portable code one would have to write a failure-checking wrapper
with slightly different implementations for different systems, and I'm
not sure if all implementations of `alloca` support such checking. As an
example of failure checking, Microsoft's `alloca` reports failure via an
SEH exception, which is not a C++ exception. One needs to use Windows
specific language extensions to catch that.

Alf P. Steinbach

unread,
Feb 17, 2017, 10:07:23 AM2/17/17
to
On 17.02.2017 14:23, Stefan Ram wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>> call has a literal value as argument). And so in standard C++ this is
>> not valid code. In standard C++ the size of an array variable must be
>> compile time constant.
>
> All of you who wonder how one might implement a stack array
> that is claimed to be portable to some extend might have a
> look at »stack_array« in the GSL (guideline support library).

I haven't looked at it because any such implementation that uses
`alloca` runs into two main problems:

• Failure of `alloca` cannot be reliably detected in a portable manner,
since the function isn't standard.

• There is no portable way to know if the resulting object is directly
on the call stack. If it isn't, then hasta la vista baby. Safety here
requires compiler support, which for portability means language support.

If instead of `alloca` one allocates in LIFO order from some buffer,
then that's another kettle of piranha. It introduces runtime checking of
LIFO call behavior, with corresponding possibility of runtime errors,
and it has that buffer laying unused most of the time in the call tree
below the buffer's declaration. Still it might be a worthwhile approach
for speeding up e.g. encoding conversions.

Perhaps also worth noting, if one should run into this esoteric
function: `std::get_temporary_buffer()` has nothing to do with stack
allocation, but rather with ¹allocating as much as currently possible up
to and possibly beyond some specified limit.


Cheers!,

- Alf

Links:
¹ See <url:
http://stackoverflow.com/questions/3264299/why-do-i-need-stdget-temporary-buffer>

0 new messages