C ++在默认构造函数中直接初始化字段与初始化列表

时间:2016-11-02 10:56:20

标签: c++

我想知道这段代码之间是否有区别:

Preference preference = findPreference("prefs_key");
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
   @Override
   public boolean onPreferenceClick(Preference preference) {
       Toast.makeText(SettingsActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
       return true;
   }
});

class Foo{
 private:
    int a = 0;
 public:
    Foo(){}
}

如果是这样,那应该是首选的? 我知道最好使用初始化列表而不是在构造函数体中赋值,但是初始化列表与在字段声明中直接初始化相比(对于基本类型,至少在这里是这样的情况)?

此外,下面的情况如下:

class Foo{
 private:
    int a;
 public:
    Foo(): a(0) {}
}

当调用非默认构造函数时:是“a”初始化两次,首先是0然后是“i”,还是直接“i”?

3 个答案:

答案 0 :(得分:16)

来自cppreference - Non-static data members

  

会员初始化
  1)在构造函数的成员初始化列表中   2)通过默认成员初始化程序,它只是成员声明中包含的大括号或等于初始化程序,如果在成员初始化程序列表中省略该成员,则使用该初始化程序。

     

如果成员具有默认成员初始值设定项并且也出现在构造函数的成员初始化列表中,则忽略默认成员初始值设定项。

总而言之,两个初始化程序都是等价的,并且可以执行它们应该执行的操作。

我更喜欢默认的成员初始化程序,如果我仍然使用默认构造函数,或者所有或大多数构造函数都将成员初始化为相同的值。

class Foo {
private:
    int a = 0;
};

如果所有构造函数都将成员初始化为某个不同的值,那么使用默认成员初始化程序的意义不大,然后各个构造函数中的显式初始化将更加清晰

class Foo {
private:
    int a;
public:
    Foo() : a(3) {}
    Foo(int i) : a(i) {}
};

答案 1 :(得分:9)

第一组示例彼此相同。

对于最后一个示例,C ++标准指定如下:

  

12.6.2初始化基础和成员

     

[...]

     

如果给定的非静态数据成员同时具有   brace-or-equal-initializer和mem-initializer,初始化   由mem-initializer指定执行,以及非静态数据   member的brace-or-equal-initializer被忽略。 [例子:给定

struct A {
int i = /∗ some integer expression with side effects ∗/ ;
A(int arg) : i(arg) { }
// ...
};
     

A(int)构造函数只需将i初始化为arg的值,   并且我的支撑或等于初始化器的副作用将不会采取   地点。 - 结束例子]

答案 2 :(得分:6)

两者完全相同。

软件工程的一个原则是DRY - 不要重复自己。 DRY指出,如果你可以避免重复相同的令牌两次,或者有两个相同的列表,那么你应该这样做。

这有几个原因。维护两个完全相同的列表出人意料地容易出错;一个被修改,或有一个错字,另一个没有。它使代码更长,这使得它更难阅读。并且避免复制粘贴编码鼓励使用一些非常强大且富有表现力的技术,这些技术可以使您所做的事情比手动执行17次更清晰。

struct foo {
  int a;
  foo():a(7) {}
};

这里我们重复了一下 - 特别是成员变量列表列出了两次。进入foo的定义后,再次出现在foo::foo的初始化列表中。如果在某处遗漏,您将获得未初始化的数据。

struct foo {
  int a = 7;
  foo() {}
};

这里我们不再重复。

struct foo {
  int a = 7;
  foo() {}
  foo(int i):a(i) {}
};

这里有一些重复,但重复是不可避免的。但是,它被最小化了。

这里有一些成本,因为有人可能会将a=7解释为“它始终从7开始”,而不是“默认值为7”。

struct foo {
  int a = 7;
  foo():a(3) {}
  foo(int i):a(i) {}
};

以上是一种可怕的反模式。