编程C++开发者

C++中直接和间接初始化对象有什么区别,使用内置类型和用户定义类型时可能会有什么后果?

用 Hintsage AI 助手通过面试

答案

在C++中,直接(direct)和间接(copy)初始化对象有所不同:

  • 直接初始化:

    MyClass obj(arg1, arg2); int x(5);

    对于类,直接调用合适的构造函数。

  • 间接初始化:

    MyClass obj = MyClass(arg1, arg2); int x = 5;

    这会创建一个临时对象,然后复制(或移动)它(使用复制或移动构造函数)。

区别:

  1. 对于内置类型,行为相同。对于类,可能调用不同的构造函数集,甚至可能会阻止初始化。
  2. 成员初始化列表在不同初始化方式下不一定等效,因为编译器的要求。
  3. 复制消除(编译器优化消除多余的复制)通常使这个区别不复存在(但并不总是如此,尤其是在C++17之前)。

示例:

struct NonCopyable { NonCopyable(int) {} NonCopyable(const NonCopyable&) = delete; }; NonCopyable a(5); // OK: 直接 NonCopyable b = NonCopyable(5); // OK, 优化情况下,C++17之前出错 NonCopyable c = 5; // 错误: 没有复制构造函数

有陷阱的问题

"如果使用C++11并启用优化编译器,copy-initialization是否可能导致比direct-initialization更多的构造函数调用?"

答案: 理论上是的。如果没有复制消除,copy-initialization创建临时对象,然后调用复制或移动构造函数。Direct-initialization始终只调用主构造函数。然而,现代编译器在启用优化时(C++17及以上)通过保证复制消除消除了这一区别。

由于不了解主题的细微差别而导致的实际错误示例


故事

在一个金融项目中使用了带有临时对象的copy-initialization,但所需类型没有复制构造函数。应用程序在旧编译器上(C++17之前)无法编译,尽管direct-init工作正常。


故事

在数据序列化工具中,程序员认为direct-init和copy-init是等效的。结果导致了大量结构的多余复制和性能下降。


故事

在初始化用户对象的全局数组时,使用了间接初始化。错误只在一个平台上显现,该平台未进行复制消除,并且由于ABI的特性而产生了隐式调用多余的构造函数。