在 CPP Con 2017 网络研讨会上,Fedor Pikus 说:“它必须是直接初始化”
这是网络研讨会的链接。
这些初始化方法有什么区别? (随后,为什么它必须是“直接”初始化?为什么“间接”初始化是“不是”?)
// C++17 Compiler
#include <atomic>
class Example
{
std::atomic<bool> m_b1 = false; // 1-h
std::atomic<bool> m_b2{ false }; // 2-h
static void doSomethng()
{
std::atomic<bool> b1 = false; // 1-f
std::atomic<bool> b2{ false }; // 2-f
std::atomic<bool> b3(false); // 3-f
// Do something
}
};
std::atomic
不可复制或移动。
在 C++17 之前,复制初始化
std::atomic<int> x = 0;
将首先从 std::atomic<int>
构造一个临时 0
,然后从该临时值直接初始化 x
。如果没有移动或复制构造函数,这将失败,因此该行无法编译。
然而 std::atomic<int> x(0);
是直接初始化,只会使用构造函数的参数 x
来构造 0
。
自 C++17 起,就没有临时的了,在任何情况下
x
都将直接由构造函数调用以 0
作为参数来初始化,因此 std::atomic
不存在不可移动的问题。从这个意义上说,这张幻灯片现在已经过时了。
尽管在这种情况下复制初始化和直接初始化的行为现在是相同的,但总的来说两者之间仍然存在差异。特别是直接初始化选择构造函数通过重载决议直接初始化变量,而复制初始化尝试找到隐式转换序列(可能通过具有不同重载决议规则的转换构造函数或转换函数)。此外,与直接初始化相比,复制初始化不考虑标记为
explicit
的构造函数。
关于问题中的代码片段。
1-h
和 1-f
是如上所述的复制初始化。 3-f
是上面的直接初始化。 2-h
和2-f
是直接列表初始化,在某些情况下其行为与其他两者不同,但在这里它与带括号的直接初始化具有相同的效果。
解释一般初始化形式之间的所有差异需要一段时间。众所周知,这是 C++ 最复杂的部分之一。