5

Is there a better way to initialise C structures in C++ code?

I can use initialiser lists at the variable declaration point; however, this isn't that useful if all arguments are not known at compile time, or if I'm not declaring a local/global instance, eg:

Legacy C code which declares the struct, and also has API's using it

typedef struct
{
    int x, y, z;
} MyStruct;

C++ code using the C library

void doSomething(std::vector<MyStruct> &items)
{
    items.push_back(MyStruct(5,rand()%100,items.size()));//doesn't work because there is no such constructor
    items.push_back({5,rand()%100,items.size()});//not allowed either

    //works, but much more to write...
    MyStruct v;
    v.x = 5;
    v.y = rand()%100;
    v.z = items.size();
    items.push_back(v);
}

Creating local instances and then setting each member one at a time (myStruct.x = 5; etc) is a real pain, and somewhat hard to read when trying to add say 20 different items to the container...

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Fire Lancer
  • 29,364
  • 31
  • 116
  • 182

6 Answers6

8

You're looking for C99 compound literals. Example code:

struct foo *foo = malloc(sizeof *foo);
*foo = (struct foo){ bar, baz };
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Sounds like a great solution, if it was supported by the compiler (VC++9) :( – Fire Lancer Jan 03 '10 at 12:57
  • 2
    this time, it's actually not the compiler's fault as compound literals are a C99 feature unsupported by C++; I misread your question and thought you were looking for a solution in C... – Christoph Jan 03 '10 at 12:59
  • see http://stackoverflow.com/questions/1705147/struct-initialization-of-the-c-c-programming-language/1705166#1705166 for some explanations and the C++0x syntax – Christoph Jan 03 '10 at 13:36
  • 1
    Complain to MS that their C compiler is archaic because it is only supporting a twenty year old standard, not the ten year old replacement standard. – Jonathan Leffler Jan 03 '10 at 15:36
8

If you can't add a constructor (which is the best solution in C++03 but you probably have compatibility constraint with C), you can write a function with the same effect:

MyStruct makeAMyStruct(int x, int y, int z)
{
    MyStruct result = { x, y, z };
    return result;
}

items.push_back(makeAMyStruct(5,rand()%100,items.size()));

Edit: I'd have checked now that C++0X offers something for this precise problem:

items.push_back(MyStruct{5,rand()%100,items.size()});

which is available in g++ 4.4.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
AProgrammer
  • 51,233
  • 8
  • 91
  • 143
3

How about:

MyStruct v = {5, rand()%100, items.size()};
items.push_back(v);
James
  • 24,676
  • 13
  • 84
  • 130
  • So to do multiple things ill have to do v1,v2,v3,v4 etc, no way to reuse the one local? – Fire Lancer Jan 03 '10 at 12:50
  • If you have v1, v2, v3, and v4, you are stuck with writing something out 4 times - unless you want them to have the same value, in which case you can do simple assignments, of course. If you had v[0], v[1], v[2], v[3] and v[4], then you could use a loop instead. – Jonathan Leffler Jan 03 '10 at 15:38
  • I'm not 100% sure about this, but I think: MyStruct vs[2] = {{1, 2, 3}, {2, 3, 4}}; will work – James Jan 03 '10 at 16:25
3

Create a function to initialize it, similar to what a C++ constructor would do.

nos
  • 223,662
  • 58
  • 417
  • 506
2

Not clear what you are asking. In C++, the obvious solution is to give the struct a constructor:

struct MyStruct {
  int x, y, z;
  MyStruct( int ax, int ay, int az ) : x( ax ), y( ay ), z( az ) {}
};
  • he's looking for a solution in C – Christoph Jan 03 '10 at 12:41
  • 1
    Then why's he tagged it C++? This is why I said I wasn't clear. –  Jan 03 '10 at 12:43
  • 4
    My guess is that he has headers which have to stay in C (legacy code shared between projects) but he want a convenient way of using the struct in C++. – AProgrammer Jan 03 '10 at 12:47
  • The thing is its a struct in some legacy C code, so unless there is some way to retrospectively add the constructor (i.e. without breaking compatibility with the C library the struct is for, and ideally without editing the declaration in the c headers themselves)? – Fire Lancer Jan 03 '10 at 12:52
1

Another option is to derive from the struct and add a constructor there.

struct MyDerivedStruct : public MyStruct
{
    MyDerivedStruct(int xi, int yi, int zi)
    {
        x = xi;
        y = yi;
        z = zi;
    }
}

Then you can use this derived type in your own code and pass it to the C library when necessary. The language should take care of implicitly converting to MyStruct when appropriate.

As a bonus, you could also add other useful member functions, perhaps even wrapping many of the legacy C functions that use this type.

TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17