成员初始化列表真的更有效吗?

spr*_*aff 7 c++ performance constructor member-initialization assignment-operator

我同意这样的共识,即通常最好在成员初始化列表中初始化C++数据成员而不是构造函数的主体,但我对此解释持怀疑态度

构建构造函数的另一种(低效)方法是通过赋值,例如:Fred::Fred() { x_ = whatever; }.在这种情况下,表达式会导致创建单独的临时对象,并且此临时对象将传递到x_对象的赋值运算符中.然后该临时对象被破坏了;.那效率很低.

这实际上是对的吗?我原以为编译器会忽略默认构造的临时对象,该对象会立即被正文中的赋值所取代.我不知道为什么我预料到这一点,但阅读了上述说法,我想我已经悄悄地假设了多年.

成员初始化列表实际上更有效吗?如果是这样,是因为这个原因吗?

Tem*_*Rex 9

Alexandrescu&Sutter的话来说(第9项)不要过早地悲观

避免过早优化并不意味着无偿地损害效率.过早的悲观化意味着写出这样的无端潜在的低效率:

•在适当传递引用时定义按值传递参数.(见第25项.)

•当前缀版本同样好时使用postfix + +.(见第28项)

•在构造函数内部使用赋值而不是初始化列表.(见第48项)

每当您在构造函数内部编写赋值时,您的代码审阅者都会处于警戒状态:这是一件特别的事情吗?他真的想要一些特殊的两阶段初始化(因为无论如何都会生成成员的隐式默认构造!).不要无缘无故地给你的代码读者带来惊喜.

请注意,Alexandrescu&Sutter在第48项中继续讨论潜在的低效率,但不要声称实际优化代码中存在实际效率低下的任何地方.这也与此无关,它是关于表达意图并避免低效率的风险.


eml*_*lai 8

使用成员初始化列表,

#include <string>

struct Fred {
  Fred() : x_("hello") { }
  std::string x_;
};

int main() {
  Fred fred;
}
Run Code Online (Sandbox Code Playgroud)

Clang 3.9.1和gcc 6.3使用-O3 -fno-exceptions(Compiler Explorer)生成以下内容:

main:                                   # @main
        xor     eax, eax
        ret
Run Code Online (Sandbox Code Playgroud)

如果我们在体内做一个任务:

#include <string>

struct Fred {
  Fred() { x_ = "hello"; }
  std::string x_;
};

int main() {
  Fred fred;
}
Run Code Online (Sandbox Code Playgroud)

两者都产生了更多的代码,例如Clang 3.9.1输出:

main:                                   # @main
        push    rbx
        sub     rsp, 32
        lea     rbx, [rsp + 16]
        mov     qword ptr [rsp], rbx
        mov     qword ptr [rsp + 8], 0
        mov     byte ptr [rsp + 16], 0
        lea     rdi, [rsp]
        xor     esi, esi
        xor     edx, edx
        mov     ecx, .L.str
        mov     r8d, 5
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)
        mov     rdi, qword ptr [rsp]
        cmp     rdi, rbx
        je      .LBB0_2
        call    operator delete(void*)
.LBB0_2:
        xor     eax, eax
        add     rsp, 32
        pop     rbx
        ret

.L.str:
        .asciz  "hello"
Run Code Online (Sandbox Code Playgroud)

所以似乎成员初始化列表确实更有效,至少在某些情况下,即使使用现代编译器也是如此.