【问题标题】:C-style initialization lists in C++, structs, and class constructorsC++、结构和类构造函数中的 C 样式初始化列表
【发布时间】:2011-11-03 02:49:39
【问题描述】:

我还在 C++ 的启蒙之路上,所以请耐心等待......

假设我有一个结构:

struct MyThing 
{
    int a, b;
};

我喜欢使用 c 风格的速记来创建一个,图 1:

MyThing mt = { 1, 2 };

然后假设我决定在我的结构中的某个地方粘贴一个方法,并且(作为我这样的人)我觉得结构并不适合方法,所以把它变成一个类:

class MyThing 
{
public:
    int a, b;
    int sum() 
    {
        return a + b;
    }
};

我的 Fig.1 仍然可以正常工作 - 一切都很好。然后我决定我最终需要一个私有方法和成员:

class MyThing 
{
private:
    int c;
    void swap() {
        c = a;
        a = b;
        b = c;
    }
public:
    int a, b;
    int sum() 
    {
        return a + b;
    }
};

此时,图 1 中的 c 样式初始化列表无法编译(无论如何在 VS 中),“non-aggregates cannot be initialized with initializer list” - 这里很好解释:http://msdn.microsoft.com/en-us/library/0s6730bb(v=vs.71).aspx

所以我切换到:

class MyThing 
{
private:
    void swap() {
        int c = a;
        a = b;
        b = c;
    }
public:
    int a, b;
    MyThing (int _a, int _b) : a(_a), b(_b) {}
    int sum() 
    {
        return a + b;
    }
};

然后将图1改为(图2)

MyThing mt(1, 2);

太棒了,毕竟,我的问题是:使用 c 风格的初始化列表(即它们更快吗?)来创建东西有什么好处吗?还是一开始也一样好:

struct MyThing
{
    int a, b;
    MyThing(int _a, int _b) : a(_a), b(_b) {}
};

并从一开始就将其用作图2?是否有任何性能影响(即使可以忽略不计)?

谢谢!

【问题讨论】:

  • “它们更快吗” - 我建议使用最自然的方法,并且只有在您真正遇到瓶颈时才担心更快。如果你在一个紧密的循环中这样做,那么可能还有其他问题......
  • 答案是“不”,它们并不比正确的初始化列表快。
  • @Mooing Duck - 这大致是我得出的结论 - 虽然用速记创建东西可以节省打字,但当它们嵌套时(即嵌套的 POD 结构),快速阅读会变得非常可怕- 而不是有构造函数,唯一的额外输入是类名(并且使用 () 而不是 {}) - 发生了什么更清楚:) 现在我也同意 awoodland - 如果它成为一个问题,请担心性能;如果我担心性能,我不太可能会创建很多很多不同的实例......谢谢你的回答:)
  • 我觉得我应该补充一下(作为我对性能的疑问的原因)我在过去 5 年里一直是一名 Java 开发人员; 1 个月后,我将搬到一家 C++ 游戏公司——这对我来说是全新的! :)

标签: c++ class list initialization


【解决方案1】:

嗯,首先,你说的例子失败了,事实上,确实有效。 (在添加构造函数之前它不会失败)

现在,请记住,一个对象只是一段记忆。因此

的二值图像
MyThing mt = { 1, 2 };        // Fig A

完全一样
int  mt[2] = { 1, 2};         // Fig B.

因此要实现 Fig A 或 Fig B,编译器只需发出:

mt    DW      0x0001        Fig C
      DW      0x0002

换句话说,零运行时间成本。

但是,如果 ctor 存在,那么它必须运行(这是 C++ 承诺的合同的一部分)。 (不可避免的运行时成本)

类似地,私有成员、基类等会干扰处理编译时分配所需的一一对应关系,如图 C 所示。

【讨论】:

  • 但是,如果构造函数是 MyThing(int x, int y) : x_(x), y_(y) { } 并且是内联定义的,则不太可能有任何运行时开销。
  • 我不明白为什么私人会员会造成问题。为什么编译器会根据可见性区分不同的成员?私有成员仍将拥有自己唯一的存储空间,并且编译器显然在编译时就知道偏移量。我不担心性能,我只是想更好地理解语言/编译器:)
  • 谢谢,我已经更新了示例,这样它使编译器失败:)
  • However, if a ctor is present, then it must be run。从技术上讲,没有。在 C++0x 1.5.9 中声明:A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible executions of the corresponding instance of the abstract machine with the same program and the same input. 例如,构造函数也可以在编译时运行。程序只需要像它已经运行一样运行。
  • § 1.9.1 更清楚:This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below4) Under the “as-if” rule an implementation is allowed to store two objects at the same machine address or not store an object at all if the program cannot observe the difference.
【解决方案2】:

使用 c 风格的初始化列表(即它们更快吗?)来创建东西有什么好处吗?

更快,更慢,真的重要吗?它在语法上通常比调用构造函数方便得多。这就是 C++0x 允许您对所有对象使用此语法的部分原因。

聚合初始化可能是免费的,作为编译时优化。编译器也有可能优化简单的构造函数。唯一知道的方法是查看生成的程序集。但除非你有真正的瓶颈,否则你不应该太在意。

【讨论】:

    猜你喜欢
    • 2011-01-06
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多