简体   繁体   中英

Struct member order causing “non-trivial designated initializers not supported” error

Previously seen here and here

I have the following structure:

struct myStruct {
    long int  mem0;
    int       mem1;
    int       mem2;
//  -- Place 1 --
    short int sh;
    -- Place 2 --  
    char      array[5];
//  -- Place 3 --
};

I try to initialize it as follows:

struct myStruct ms1 = {
      mem0 : 124,
      mem1 : 120,
      mem2 : 99,
      mem3 : 12,
};                      // Line 36

If I place any of the following lines in place 2 or place 3

    char      mem3;
    int       mem3;

I get the following error:

Azulejo-Main-Engine-1v2-4% g++ test2.cpp -o test2
test2.cpp: In function ‘int main()’:
test2.cpp:36:5: sorry, unimplemented: non-trivial designated initializers not supported
     };
     ^
Azulejo-Main-Engine-1v2-4% 

However, If I place it in place 1, my program compiles (and executes as expected). Can you please explain me why this is the case?.

I'm trying to port C code into C++. How can prevent this kind of errors?. I don't have any control on the structure declarations used by the code.

Azulejo-Main-Engine-1v2-4% g++ --version
g++ (GCC) 5.2.0

"sorry, unimplemented: <...>" always means that the compiler simply hasn't been updated to allow this yet. That's regardless of whether it will be allowed in the future, whether it is allowed by the standard, or whether it even makes sense.

As mentioned in the comments, this is not valid C++, this is a compiler extension. You can avoid problems of this kind by limiting yourself to valid C++. GCC will diagnose this and many other extensions if you pass it the -pedantic flag. It will treat such extensions as a hard error if you pass it the -pedantic-errors flag. If you then see that you are writing non-portable C++, update your code to make it portable, either by:

struct myStruct ms1 = {
  124,
  120,
  99,
  12
};

which requires you to place mem3 after mem2 , or by

struct myStruct ms1 {};
ms1.mem0 = 124;
ms1.mem1 = 120;
ms1.mem2 = 99;
ms1.mem3 = 12;

which does not require any specific placement of mem3 , or by adding a constructor to your myStruct taking mem0 ... mem3 as parameters.


Some extra details about the complications of this extension:

The initialisation of structures in C++ normally happens in whatever order the fields are declared. This makes handling exceptions fairly easy: the fields can be destroyed in the reverse order. If not all fields had been constructed yet, then start the destruction at the last field that had been constructed.

If you allow fields to be initialised in arbitrary order, then the destruction gets complicated. Given struct myStruct ms1 { mem1: f(), mem0: g() }; , if g throws an exception, then either mem1 was already initialised and needs to be destructed, without mem0 also getting destructed, or the compiler rearranges the initialisers, meaning g() gets called before f() . The former is hard to get right in the compiler, the latter is very unintuitive.

A special exception could be made for trivially destructable fields, where no user code needs to be run when the fields are destroyed, but it hasn't been implemented yet.

If you place mem3 right after mem2 , then the problem is avoided: the order of initialisation matches the field order exactly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM