[c++] C++ Structure Initialization

Is it possible to initialize structs in C++ as indicated below

struct address {
    int street_no;
    char *street_name;
    char *city;
    char *prov;
    char *postal_code;
};
address temp_address =
    { .city = "Hamilton", .prov = "Ontario" };

The links here and here mention that it is possible to use this style only in C. If so why is this not possible in C++? Is there any underlying technical reason why it is not implemented in C++, or is it bad practice to use this style. I like using this way of initializing because my struct is big and this style gives me clear readability of what value is assigned to which member.

Please share with me if there are other ways through which we can achieve the same readability.

I have referred the following links before posting this question

  1. C/C++ for AIX
  2. C Structure Initialization with Variable
  3. Static structure initialization with tags in C++
  4. C++11 Proper Structure Initialization

This question is related to c++

The answer is


This feature is called designated initializers. It is an addition to the C99 standard. However, this feature was left out of the C++11. According to The C++ Programming Language, 4th edition, Section 44.3.3.2 (C Features Not Adopted by C++):

A few additions to C99 (compared with C89) were deliberately not adopted in C++:

[1] Variable-length arrays (VLAs); use vector or some form of dynamic array

[2] Designated initializers; use constructors

The C99 grammar has the designated initializers [See ISO/IEC 9899:2011, N1570 Committee Draft - April 12, 2011]

6.7.9 Initialization

initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }
initializer-list:
    designation_opt initializer
    initializer-list , designationopt initializer
designation:
    designator-list =
designator-list:
    designator
    designator-list designator
designator:
    [ constant-expression ]
    . identifier

On the other hand, the C++11 does not have the designated initializers [See ISO/IEC 14882:2011, N3690 Committee Draft - May 15, 2013]

8.5 Initializers

initializer:
    brace-or-equal-initializer
    ( expression-list )
brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
initializer-clause:
    assignment-expression
    braced-init-list
initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt
braced-init-list:
    { initializer-list ,opt }
    { }

In order to achieve the same effect, use constructors or initializer lists:


After my question resulted in no satisfying result (because C++ doesn't implement tag-based init for structures), I took the trick I found here: Are members of a C++ struct initialized to 0 by default?

For you it would amount to do that:

address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";

This is certainly the closest to what you wanted originally (zero all the fields except those you want to initialize).


You can even pack Gui13's solution into single initialization statement:

struct address {
                 int street_no;
                 char *street_name;
                 char *city;
                 char *prov;
                 char *postal_code;
               };


address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);

Disclaimer: I don't recommend this style


In C++ the C-style initializers were replaced by constructors which by compile time can ensure that only valid initializations are performed (i.e. after initialization the object members are consistent).

It is a good practice, but sometimes a pre-initialization is handy, like in your example. OOP solves this by abstract classes or creational design patterns.

In my opinion, using this secure way kills the simplicity and sometimes the security trade-off might be too expensive, since simple code does not need sophisticated design to stay maintainable.

As an alternative solution, I suggest to define macros using lambdas to simplify the initialization to look almost like C-style:

struct address {
  int street_no;
  const char *street_name;
  const char *city;
  const char *prov;
  const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE

The ADDRESS macro expands to

[] { address _={}; /* definition... */ ; return _; }()

which creates and calls the lambda. Macro parameters are also comma separated, so you need to put the initializer into brackets and call like

address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));

You could also write generalized macro initializer

#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE

but then the call is slightly less beautiful

address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));

however you can define the ADDRESS macro using general INIT macro easily

#define ADDRESS(x) INIT(address,x)

In GNUC++ (seems to be obsolete since 2.5, a long time ago :) See the answers here: C struct initialization using labels. It works, but how?), it is possible to initialize a struct like this:

struct inventory_item {
    int bananas;
    int apples;
    int pineapples;
};

inventory_item first_item = {
    bananas: 2,
    apples: 49,
    pineapples: 4
};

The field identifiers are indeed C initializer syntax. In C++ just give the values in the correct order without the field names. Unfortunately this means you need to give them all (actually you can omit trailing zero-valued fields and the result will be the same):

address temp_address = { 0, 0, "Hamilton", "Ontario", 0 }; 

I found this way of doing it for global variables, that does not require to modify the original structure definition :

struct address {
             int street_no;
             char *street_name;
             char *city;
             char *prov;
             char *postal_code;
           };

then declare the variable of a new type inherited from the original struct type and use the constructor for fields initialisation :

struct temp_address : address { temp_address() { 
    city = "Hamilton"; 
    prov = "Ontario"; 
} } temp_address;

Not quite as elegant as the C style though ...

For a local variable it requires an additional memset(this, 0, sizeof(*this)) at the beginning of the constructor, so it's clearly not worse it and @gui13 's answer is more appropriate.

(Note that 'temp_address' is a variable of type 'temp_address', however this new type inherit from 'address' and can be used in every place where 'address' is expected, so it's OK.)


As others have mentioned this is designated initializer.

This feature is part of C++20


It's not implemented in C++. (also, char* strings? I hope not).

Usually if you have so many parameters it is a fairly serious code smell. But instead, why not simply value-initialize the struct and then assign each member?


I might be missing something here, by why not:

#include <cstdio>    
struct Group {
    int x;
    int y;
    const char* s;
};

int main() 
{  
  Group group {
    .x = 1, 
    .y = 2, 
    .s = "Hello it works"
  };
  printf("%d, %d, %s", group.x, group.y, group.s);
}

You can just initialize via a constructor:

struct address {
  address() : city("Hamilton"), prov("Ontario") {}
  int street_no;
  char *street_name;
  char *city;
  char *prov;
  char *postal_code;
};

It is possible, but only if the struct you're initializing is a POD (plain old data) struct. It cannot contain any methods, constructors, or even default values.


Inspired by this really neat answer: (https://stackoverflow.com/a/49572324/4808079)

You can do lamba closures:

// Nobody wants to remember the order of these things
struct SomeBigStruct {
  int min = 1;
  int mean = 3 ;
  int mode = 5;
  int max = 10;
  string name;
  string nickname;
  ... // the list goes on
}

.

class SomeClass {
  static const inline SomeBigStruct voiceAmps = []{
    ModulationTarget $ {};
    $.min = 0;  
    $.nickname = "Bobby";
    $.bloodtype = "O-";
    return $;
  }();
}

Or, if you want to be very fancy

#define DesignatedInit(T, ...)\
  []{ T ${}; __VA_ARGS__; return $; }()

class SomeClass {
  static const inline SomeBigStruct voiceAmps = DesignatedInit(
    ModulationTarget,
    $.min = 0,
    $.nickname = "Bobby",
    $.bloodtype = "O-",
  );
}

There are some drawbacks involved with this, mostly having to do with uninitialized members. From what the linked answers comments say, it compiles efficiently, though I have not tested it.

Overall, I just think it's a neat approach.


I faced a similar problem today, where I have a struct that I want to fill with test data which will be passed as arguments to a function I'm testing. I wanted to have a vector of these structs and was looking for a one-liner method to initialize each struct.

I ended up going with a constructor function in the struct, which I believe was also suggested in a few answers to your question.

It's probably bad practice to have the arguments to the constructor have the same names as the public member variables, requiring use of the this pointer. Someone can suggest an edit if there is a better way.

typedef struct testdatum_s {
    public:
    std::string argument1;
    std::string argument2;
    std::string argument3;
    std::string argument4;
    int count;

    testdatum_s (
        std::string argument1,
        std::string argument2,
        std::string argument3,
        std::string argument4,
        int count)
    {
        this->rotation = argument1;
        this->tstamp = argument2;
        this->auth = argument3;
        this->answer = argument4;
        this->count = count;
    }

} testdatum;

Which I used in in my test function to call the function being tested with various arguments like this:

std::vector<testdatum> testdata;

testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5));
testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1));
testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7));

for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) {
    function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count);
}

I know this question is quite old, but I found another way of initializing, using constexpr and currying:

struct mp_struct_t {
    public:
        constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
        constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
        constexpr mp_struct_t another_member(int member) { return {member1, member,     member2}; }
        constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }

    int member1, member2, member3;
};

static mp_struct_t a_struct = mp_struct_t{1}
                           .another_member(2)
                           .yet_another_one(3);

This method also works for global static variables and even constexpr ones. The only disadvantage is the bad maintainability: Everytime another member has to be made initializable using this method, all member initialization methods have to be changed.