Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用成员初始值设定项列表会使初始化稍微快一点吗?_C++_C++11_Initializer List - Fatal编程技术网

C++ 使用成员初始值设定项列表会使初始化稍微快一点吗?

C++ 使用成员初始值设定项列表会使初始化稍微快一点吗?,c++,c++11,initializer-list,C++,C++11,Initializer List,Bjarne Stroustrup在其《使用C++编程、原则和实践》一书中介绍了成员初始值设定项列表的概念,见第314-316页(§9.4.4)。他举了以下例子: // Simple Date (year, month, day) class Date { public: Date(int yy, int mm, int dd): y{yy}, m{mm}, d{dd} { //... } private: int y, m, d; }; 在

Bjarne Stroustrup在其《使用C++编程、原则和实践》一书中介绍了成员初始值设定项列表的概念,见第314-316页(§9.4.4)。他举了以下例子:

// Simple Date (year, month, day)

class Date
{
public:
    Date(int yy, int mm, int dd): y{yy}, m{mm}, d{dd}
    {
        //...
    }

private:
    int y, m, d;
};
在第315页,他说:

我们本可以写:

Date::Date(int yy, int mm, int dd)  // constructor
{
    y = yy;
    m = mm;
    d = dd;
}
但是,原则上,我们将首先对成员进行默认初始化,然后为其分配值

因此,我是否可以得出这样的结论:使用成员初始值设定项列表可以使代码稍微快一点?当然,在现代PC上没有人会注意到。但是我正打算用C++来进行嵌入式开发。 编辑:
我会进一步说明我的问题。“稍微快一点”实际上是指“所涉及的CPU周期更少”。

我也同意这个例子的潜在效率提高几乎是零。但是对于更大的类和结构,它可能在微控制器上变得明显。

< P> C++标准指定“默认初始化”如下:

[dcl.init]

默认初始化T类型的对象意味着:

-如果T是 (可能是cv限定的)类类型(第9条),默认 调用T的构造函数(12.1)(初始化为 如果T没有默认构造函数或重载解析,则格式错误 (13.3)导致歧义或功能被删除或 无法从初始化上下文访问)

-如果T是一个 数组类型,每个元素默认初始化

-否则,不执行初始化

你的班级成员都是普通的、花园式的,
int
s。他们不是班级。它们不是数组。因此,在
int
s的情况下,默认初始化不执行任何操作


在两个示例中,我希望大多数编译器生成相同的代码。无论如何,这没有什么区别。

在第二个示例中,您没有初始化,而是为已经初始化的变量赋值。变量在进入构造函数之前被初始化(默认构造),因此实际上您要设置它们两次

int
没有任何特定的默认初始值设定项,因此您不会注意到,而是尝试使用不同的代码


所以你看,它们绝对不是等价物。实际上,例如,您不能在构造函数中用
int
s
指定
const
字段?没有什么区别。尝试一些重的类。如果没有副作用,这都是优化出来的。使一个成员常量。现在哪条路可行?这些决策涉及的不仅仅是绩效。始终使用成员初始值设定项列表作为默认值。您的问题有一个明显的答案。“在一个非真空阶段做某事会比两个非真空阶段快吗?”当然,如果这两个阶段在指令计数方面具有可比性,那么删除一个会节省CPU周期……在许多实际情况下,使用初始化列表(或类内初始化器)比使用构造函数体更快。在某些情况下,编译器可以将其全部优化为相同的内容(但不要指望它)。尽可能使用初始化列表。谢谢@SamVarshavchik。你能想出一个例子来说明它的重要性吗?这是引用《标准》中的话指出的。如果类成员本身是一个(另一个)类,其构造函数实际上做了一些事情,那么这很重要。谢谢@SamVarshavchik:-)使用初始值设定项列表可能仍然是一个更好的习惯。如果你研究这个主题,有些事情只能通过初始化列表来完成。哇,有趣的代码片段!因此,在您的示例中:(1)“在构造函数中赋值”导致对Foo构造函数的3次调用,(2)“在初始值设定项列表中赋值”只导致对Foo构造函数的1次调用。这3次调用Foo构造函数=>这意味着内存中某处有3个Foo对象?实际上,对于两次调用
Foo
构造函数和一个复制赋值运算符,
Foo()
在构造
Bar
时被调用。然后调用
Foo(int)
来构造一个临时
Foo
,该临时
Foo
通过常量引用传递给
Foo
中包含的
Bar
operator=
,后者复制该值。然后,临时文件被销毁。成员初始值设定项列表避免了这一点,因为它是初始化对象的受限位置,因此编译器可以自由地执行任何他想要的操作。它们不仅仅是代码块中的赋值,就像在构造函数中一样。太棒了!我只是想知道为什么在你的例子中需要“const”。如果没有,它是否也会工作?是的,首先调用
Foo(int)
,因为函数/构造函数的参数在调用
Bar
的构造函数之前进行计算,该构造函数将在输入构造函数代码之前初始化所有成员(如果在成员初始值设定项列表中没有提供初始化,则将使用默认初始化)。
#include <iostream>
using namespace std;

class Foo
{
  int x;

public:
  Foo() : x(0) { cout << "Foo()" << endl; }
  Foo(int x) : x(x) { cout << "Foo(int)" << endl; }
  Foo& operator=(const Foo& o) { 
    cout << "Foo::operator=(const Foo&)" << endl; 
    this->x = o.x; return *this;
  }
};

class Bar
{
   Foo foo;
public:  
   Bar(const Foo& foo) { this->foo = foo; }
   Bar(bool, const Foo& foo) : foo(foo) { }
};

int main() {
  cout << "Assigned in constructor" << endl;
  Bar bar = Bar(Foo(5));
  cout << "Assigned in initializer list" << endl;
  Bar bar2 = Bar(false, Foo(5));
}
Assigned in constructor
Foo(int)
Foo()
Foo::operator=(const Foo&)
Assigned in initializer list
Foo(int)