Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ error: "taking address of temporary array"

Tags:

c++

arrays

I am trying to declare an array inside an if-statement. I wrote my code this way so that the object stays in scope once the if-block exits, but now I have a new issue: "taking address of temporary array". How can I re-write this in an alternative way so that maskArray is assigned the correct values?

int* maskArray;
if(conditional==true)
   maskArray = (int[9]) {0,1,0,1,-4,1,0,1,0};
like image 470
Bobazonski Avatar asked Oct 05 '15 05:10

Bobazonski


3 Answers

While it is true that the original construct is not valid in C++, standard C++ does have a fairly similar feature: one can create a temporary array using an explicit type name and list-initializer

using I9 = int [9];
I9{ 0, 1, 0, 1, -4, 1, 0, 1, 0 };

The above is valid C++ syntax for a temporary array object. But if you try using it in GCC, you will quickly discover that GCC refuses to apply array-to-pointer conversion to such temporary arrays, e.g.

using C10 = char [10];
C10 str;
std::strcpy(str, C10{ 'a', 'b', 'c' });
// GCC: error: taking address of temporary array

The above is perfectly valid C++, but a bug in GCC prevents it from compiling. Clang and MSVC accept this code.

In your original code you are actually relying on a GCC extension, which allows you to use C-style compound literal syntax in C++ code, but this extension apparently happens to suffer from the very same bug as described above.

like image 129
AnT Avatar answered Sep 23 '22 02:09

AnT


Assuming you aren't going to later modify what maskArray points to, then the best/simplest solution is:

const int* maskArray;
if(conditional==true)
{
     static const int myArray[9] = {0,1,0,1,-4,1,0,1,0};
     maskArray = &myArray[0];
}

Static const works if you never plan to update the array, but if you're going to update it, you need a separate copy. This may be created either on the stack or on the heap. To create it on the stack:

int* maskArray;
int myArray[9] = {0,1,0,1,-4,1,0,1,0};
if(conditional==true)
{
     maskArray = &myArray[0];
}
// when `myArray` goes out of scope, the pointer stored in maskArray will be useless! If a longer lifetime is needed, use the heap (see below).

To dynamically create new copies of the array on the heap, you need to allocate the memory using new[]. The advantage of this is that it can be kept around for as long as it's useful before you decide to delete it.

int* maskArray;
if(conditional==true)
{
     maskArray = new int[9] {0,1,0,1,-4,1,0,1,0};
}

Remember to delete is later using delete[] maskArray!

like image 43
VoidStar Avatar answered Sep 23 '22 02:09

VoidStar


(int[9]) {0,1,0,1,-4,1,0,1,0} creates a temporary array which will be destroyed as soon as the full statement is completed. (Note, this is technically not C++, but a C99 feature which your compiler is supporting as an extension in C++.)

maskArray = (int[9]) {0,1,0,1,-4,1,0,1,0}; takes that temporary array, converts it to a pointer and stores that pointer in maskArray. As soon as this statement completes, the temporary array will be destroyed and the value in maskArray will no longer be valid.

The only way it's acceptable to use such a temporary array is to use it in that very same statement, such as by passing it to a function which will use it:

void foo(int (&arr)[9]);

foo((int[9]) {0,1,0,1,-4,1,0,1,0});

This is okay because even though the temporary array is destroyed, it's only destroyed after the function returns and nothing is using the array. (And the function had better not somehow store long-lived references or pointers into the array, but then that's no different from normal.)

like image 20
bames53 Avatar answered Sep 22 '22 02:09

bames53