5

Is it possible to invoke aggregate initialization within my own definition of the default ctor?

GCC complains "error: constructor delegates to itself" with the below code:

struct X {
  int x, y, z, p, q, r;
  X(): x{}, y{}, z{}, p{}, q{}, r{} { }  // cumbersome
//X(): X{} { }  // the idea is nice but doesn't compile
};

I'm using memset(this, 0, sizeof(*this)) in the ctor body at the moment.

nodakai
  • 7,773
  • 3
  • 30
  • 60

3 Answers3

1

One way would be to fool overload resolution in the following way:

struct X {
  int x, y, z, p, q, r;
  X(int) : x{}, y{}, z{}, p{}, q{}, r{} { }
  X() : X(0) { }
};

Another way would be to use in-class default member initialization:

struct X {
  int x = 0, y = 0, z = 0, p = 0, q = 0, r = 0;
};

In your specific example you could also do:

struct X {
  std::array<int, 6> vars{};
};
101010
  • 41,839
  • 11
  • 94
  • 168
0

You may use the CRTP to do this.

template<class C>
struct ZeroInitialized
{
    ZeroInitialized() { memset((C*)this, 0, sizeof(C)); }
};


struct A : ZeroInitialized<A>
{
    int x, y, z, p, q, r;
};

But I'm making no guarantees this is safe.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

Use factory pattern - move the body of your constructor to separate class:

struct X {
  int x, y, z, p, q, r;
};

struct XFactory {
  X create();
};

X XFactory::create()
{
   X x{};
   // do needed modification
   return x;
}

Although I'd always prefer factory pattern - there is also other way more aligned to your explicit needs - define default constructor for each of your member data:

template <typename T>
struct DefaultConstructibleData
{
   T data;
   DefaultConstructibleData() data{} {} 
};

And use it:

struct X {
  DefaultConstructibleData<int> x, y, z, p, q, r;
  X() 
  {         
       // do whatever you needs to do
       // all x,y,... are already constructed to their defaults
  }
};
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • Redundant copying galore. And it doesn't remove any of the cumbersome code the OP complained about, just moves it outside of the c'tor. – StoryTeller - Unslander Monica Jun 02 '16 at 14:03
  • @StoryTeller RVO - https://en.wikipedia.org/wiki/Return_value_optimization - prevents from redundant copying... – PiotrNycz Jun 02 '16 at 14:04
  • RVO is an optimization (not a guarantee), and there must still be at least on copy made if you do assignments. Not to mention, you make it impossible to create const objects. – StoryTeller - Unslander Monica Jun 02 '16 at 14:05
  • I stand corrected on the const objects front. Had a moment of confusion. But your copies are not all optimized out. Semantically the compiler can't do that. That's why move c'tor were invented in the first place. – StoryTeller - Unslander Monica Jun 02 '16 at 14:12
  • @StoryTeller Even if RVO is not working here (it won't for copmplicated classes) then this x here is eXpiring Value here - so move constructor will be invoked here automatically - no copying... unless moving not defined. Of course for struct filled with int's - RVO is practically always working... – PiotrNycz Jun 02 '16 at 14:15