【问题标题】:Member initialization while using delegated constructor使用委托构造函数时的成员初始化
【发布时间】:2012-08-24 18:41:08
【问题描述】:

我已经开始尝试 C++11 标准,我发现 this 问题描述了如何从同一类中的另一个 ctor 调用您的 ctor 以避免使用 init 方法等。现在我正在用类似这样的代码尝试同样的事情:

hpp:

class Tokenizer
{
public:
  Tokenizer();
  Tokenizer(std::stringstream *lines);
  virtual ~Tokenizer() {};
private:
  std::stringstream *lines;
};

cpp:

Tokenizer::Tokenizer()
  : expected('=')
{
}

Tokenizer::Tokenizer(std::stringstream *lines)
  : Tokenizer(),
    lines(lines)
{
}

但这给了我错误: In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’: /path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegation 我尝试将 Tokenizer() 部分移到列表中的第一个和最后一个,但这没有帮助。

这背后的原因是什么,我应该如何解决?我尝试用this->lines = lines;lines(lines) 移动到身体上,效果很好。但我真的很想能够使用初始化列表。

【问题讨论】:

    标签: c++ gcc c++11 ctor-initializer


    【解决方案1】:

    当您将成员初始化委托给另一个构造函数时,假设另一个构造函数完全初始化对象,包括所有成员(即在您的示例中包括 lines 成员)。因此,您不能再次初始化任何成员。

    标准中的相关引用是(强调我的):

    (§12.6.2/6) mem-initializer-list 可以使用任何表示构造函数类本身的 class-or-decltype 委托给构造函数类的另一个构造函数。如果一个 mem-initializer-id 指定了构造函数的类,它应该是唯一的 mem-initializer;构造函数是委托构造函数,选择的构造函数是目标构造函数。 [...]

    您可以通过定义带参数的构造函数的版本first来解决这个问题:

    Tokenizer::Tokenizer(std::stringstream *lines)
      : lines(lines)
    {
    }
    

    然后使用委托定义默认构造函数:

    Tokenizer::Tokenizer()
      : Tokenizer(nullptr)
    {
    }
    

    作为一般规则,您应该完全指定采用最多参数的构造函数版本,然后从其他版本进行委托(使用所需的默认值作为委托中的参数)。

    【讨论】:

    • 乍一看似乎违反直觉,但实际上确实有帮助!
    • 如果你正在初始化的对象不是指针怎么办?
    • @JacobWaters 那么您很可能会使用适当的默认初始化。假设lines 的类型为A,你可以说: Tokenizer(A()) 用于初始化列表。如果A 很大并且没有移动构造器或者以某种方式不适合高效/可优化的复制,这可能会出现问题。在这种情况下,最好不要使用这种委托。
    猜你喜欢
    • 2012-11-15
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    相关资源
    最近更新 更多