具有聚合初始化的 C++11 构造函数委托

Posted

技术标签:

【中文标题】具有聚合初始化的 C++11 构造函数委托【英文标题】:C++11 constructor delegation with aggregate initialization 【发布时间】: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)) 正在伤害我内心的平静... 【参考方案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,很好,在这个可憎的事情上没有提到你 :)

以上是关于具有聚合初始化的 C++11 构造函数委托的主要内容,如果未能解决你的问题,请参考以下文章

C11构造函数的改善

[C++11 类的改进] --- 继承构造函数和委托构造函数

C++11 继承构造函数和委托构造函数

C++11 继承构造函数和委托构造函数

[C++11 类的改进] --- 继承构造函数和委托构造函数

[C++11 类的改进] --- 继承构造函数和委托构造函数