【问题标题】:C++11 constructor delegation with aggregate initialization具有聚合初始化的 C++11 构造函数委托
【发布时间】:2016-10-02 06:23:42
【问题描述】:

是否可以在我自己定义的默认 ctor 中调用聚合初始化?

GCC 使用以下代码抱怨“错误:构造函数委托给自身”:

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
};

我现在在 ctor 正文中使用memset(this, 0, sizeof(*this))

【问题讨论】:

  • 如果 X 本身不必是聚合,您可以将 x, y, z... 移动到基类,并在成员初始化列表中聚合初始化该基类
  • @PiotrSkotnicki 很有趣的想法,但如果我在生产代码中这样做,我的同事们会皱眉头。
  • memset(this, 0, sizeof(*this)) 正在伤害我内心的平静...

标签: c++ c++11 constructor aggregate-initialization delegating-constructor


【解决方案1】:

使用factory pattern - 将构造函数的主体移动到单独的类:

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

struct XFactory {
  X create();
};

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

虽然我总是更喜欢工厂模式 - 还有其他方式更符合您的明确需求 - 为您的每个成员数据定义默认构造函数:

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

并使用它:

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
  }
};

【讨论】:

  • 大量冗余复制。而且它不会删除 OP 抱怨的任何繁琐代码,只是将其移到 c'tor 之外。
  • @StoryTeller RVO - en.wikipedia.org/wiki/Return_value_optimization - 防止重复复制...
  • RVO 是一种优化(不是保证),如果你做作业,至少必须有一个副本。更不用说,您无法创建 const 对象。
  • 我在前面的 const 对象上得到了纠正。有一瞬间的困惑。但是您的副本并未全部优化。从语义上讲,编译器无法做到这一点。这就是最初发明 move c'tor 的原因。
  • @StoryTeller 即使 RVO 在这里不起作用(它不适用于复制类),那么这里的 x 这里是过期值 - 所以移动构造函数将在这里自动调用 - 没有复制......除非移动未定义。当然对于填充 int 的结构 - RVO 实际上总是在工作......
【解决方案2】:

一种方法是通过以下方式欺骗重载决议:

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

另一种方法是使用类内默认成员初始化:

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

在您的具体示例中,您也可以这样做:

struct X {
  std::array<int, 6> vars{};
};

【讨论】:

  • 我认为 OP 打算完全删除 x{}, y{}, z{}, p{}, q{}, r{} 部分
  • @PiotrSkotnicki OP 说他/她现在正在使用 memset(this, 0, sizeof(*this))
  • 不,OP 基本上是问如何在 C++ 中复制 Java 的 this() condtructor 调用
  • @101010 是的,所以他想用一个函数初始化分配结构的部分内存(结构内部的变量)。所以你们都做对了。
【解决方案3】:

您可以使用 CRTP 来执行此操作。

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


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

但我不保证这是安全的。

【讨论】:

  • 这不是我的意思 :( 。聚合初始化是指 struct A : B { A() : B{} {} };struct B { int x, y, z; };
  • @PiotrSkotnicki,你的意思是将成员推到基础上,但它并没有解决 OP 的问题,只是重命名了它出现的类。我合并了这两种方法。
  • @PiotrSkotnicki,很好,在这个可憎的事情上没有提到你 :)
猜你喜欢
  • 2012-11-15
  • 1970-01-01
  • 2012-12-31
  • 2013-01-29
  • 2012-08-24
  • 2016-11-28
  • 2018-01-08
  • 1970-01-01
  • 2020-12-27
相关资源
最近更新 更多