C++ error: “taking address of temporary array”

后端 未结 6 1881
渐次进展
渐次进展 2021-01-01 04:42

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: \"tak

相关标签:
6条回答
  • 2021-01-01 05:05

    You can only initialize an array when it is declared. So if it need to be scoped in a loop declare an array inside the loop:

    int* maskArray;
    if (conditional == true) {
        int locArray[] = {0,1,0,1,-4,1,0,1,0};
        maskArray = locArray;
        // ...
    } // locArray goes out of scope here
    // BEWARE : maskArray is now a dangling pointer (maskArray = NULL is safer)
    

    As noticed by M.M, you can avoid the dangling maskArray by declaring it inside the block, (or by omitting it if you can directly use locArray):

    if (conditional==true) {
        int locArray[] = {0,1,0,1,-4,1,0,1,0};
        int *maskArray = locArray; // may be fully omitted if locArray is enough
    }
    
    0 讨论(0)
  • 2021-01-01 05:16
    if (...)
    {
      static int a[9] = { ... };
      maskArray = a;
    }
    
    0 讨论(0)
  • 2021-01-01 05:19

    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!

    0 讨论(0)
  • 2021-01-01 05:26

    (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.)

    0 讨论(0)
  • 2021-01-01 05:28

    You can use a temporary array to achieve this

    int temp [] = {0,1,0,1,-4,1,0,1,0};
    size_t n = sizeof(temp)/sizeof(int);
    
    if (condition == true )
    {
       maskArray = new int[n]{0,1,0,1,-4,1,0,1,0};
    }
    
    // ...
    
    delete [] maskArray; // Free memory after use
    

    Or simply use a std::vector

    std::vector<int> maskArray;
    
    if( condition == true )
    {
      maskArray = {0,1,0,1,-4,1,0,1,0}; // C++11 initializer_list vector assignment
    }
    
    0 讨论(0)
  • 2021-01-01 05:31

    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.

    0 讨论(0)
提交回复
热议问题