【问题标题】:Benefits of Initialization lists初始化列表的好处
【发布时间】:2010-12-08 14:39:00
【问题描述】:

我知道使用初始化列表的好处是,它们在初始化非内置类成员时提供了效率。例如,

Fred::Fred() : x_(whatever) { }

优于,

Fred::Fred() { x_ = whatever; }

如果 x 是自定义类的对象。除此之外,为了保持一致性,这种风格甚至与内置类型一起使用。

这样做最常见的好处是提高了性能。如果表达式whatever 与成员变量x_ 的类型相同,则whatever 表达式的结果直接在x_ 内部构造——编译器不会制作对象的单独副本。

对于另一种风格,表达式whatever 会导致创建一个单独的临时对象,并将这个临时对象传递给x_ 对象的赋值运算符。然后该临时对象在 ; 处被破坏。那是低效的。

问题
在以下示例中使用初始化列表是否有任何效率提升。 我认为没有收获。第一个版本调用字符串的复制构造函数,另一个调用字符串的赋值运算符(没有创建任何临时的)。对吗?

class MyClass
{
public:
    MyClass(string n):name(n) { }
private:
    string name;
};

class MyClass
{
public:
    MyClass(string n)
    {
        name=n;
    }
private:
    string name;
};

【问题讨论】:

  • 初始化列表的另一个好处(如果你想称之为好处)是它们是初始化某些事物的唯一方法 - 使用非默认 ctor、const 成员和参考成员。
  • 另外,如果您担心性能,我宁愿使用 'const&' 来传递参数,而不是复制。
  • 你怎么会有Fred::Fred() : x_(whatever)?弗雷德不接受任何论据。
  • 在 Visual Studio 2017 专业版“内存视图”中很容易看到内存地址看起来不同,因此在此证伪了所有错误假设。事实上,我开始明白类初始化列表的真正目的是为了const,而不是为了速度。

标签: c++ initialization-list


【解决方案1】:

第二个版本是调用字符串的默认 ctor,然后是字符串的复制赋值运算符——与第一个版本相比,肯定会有(轻微的)效率损失,它直接调用 c 的 copy-ctor(例如,取决于字符串的实现,可能有一些微小结构的无用分配然后释放)。为什么不总是使用正确的方法?-)

【讨论】:

  • 是的。您还应该提到,有时,“正确的方式”是您拥有的唯一选项。如果您需要初始化引用或 const 类型,或者没有赋值运算符的东西,您没有太多选择
  • @jalf true,但不直接适用于 OP 提供的代码(仅适用于使用 string& 成员而不是 string 成员的变体)。
  • 你不是说它在调用string的复制构造函数,然后是它的赋值运算符吗?
  • 这不应该是公认的答案。类初始化列表的主要目的主要是为了const 而枯萎它是关于速度只是偶然的。
【解决方案2】:

请记住,复制构造函数和赋值运算符之间存在明显区别:

  • 复制 ctor构造一个新对象,使用其他实例作为从中获取初始化信息的位置。
  • 赋值运算符修改已经完全构造的已经存在的对象(即使它只是使用默认构造函数)

所以在你的第二个例子中,到那时,已经完成了一些工作来创建name

 name=n;

已到达。

但是,很可能(尤其是在这个简单的示例中)完成的工作非常小(可能只是将string 对象中的一些数据成员归零)并且在优化的构建中完全优化了工作。但是尽可能使用初始化列表仍然被认为是一种很好的形式。

【讨论】:

  • 说得很好。虽然这是基本的,但对于像我这样学习 C 和汇编的人来说,这是很容易忽略/忘记的。
【解决方案3】:

我认为初始化 const 数据成员的唯一方法是在初始化列表中

例如。在标题中:

class C
{
    C();
private:
    const int x;
    int y;
}

以及cpp文件中的:

C::C() :
    x( 10 ),
    y( 10 )
{
    x = 20; // fails
    y = 20;
}

【讨论】:

  • 这应该是公认的答案。 const 的用法在这里清晰而毫无疑问是主要明确的水晶般清晰的用法,仅在 class initialization list 内有效。
【解决方案4】:

这是初始化成员的好方法:

  • 是常量
  • 没有默认构造函数(它是私有的)

【讨论】:

    【解决方案5】:

    我们也可以通过初始化列表执行constructor delegation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-24
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 2011-06-05
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      相关资源
      最近更新 更多