为什么对象的初始化会调用复制构造函数?

Why does the initialisation of an object invoke the copy constructor?

考虑以下最小工作示例:

#include <atomic>

int main() {
  ::std::atomic<bool> a = false;
}

atomic 的复制构造函数和复制赋值都被显式删除。但是,这应该调用 ctor taking exactly a bool.

g++ 和 clang++ 都抱怨这一行试图调用 atomic:

的复制构造函数
$ g++ -std=c++1z a.cpp 
a.cpp: In function ‘int main()’:
a.cpp:4:27: error: use of deleted function ‘std::atomic<bool>::atomic(const std::atomic<bool>&)’
   ::std::atomic<bool> a = false;
                           ^~~~~
$ clang++ -std=c++1z a.cpp 
a.cpp:4:23: error: copying variable of type '::std::atomic<bool>' invokes deleted constructor
  ::std::atomic<bool> a = false;
                      ^   ~~~~~

他们为什么要复制 atomic

它试图调用复制构造函数,因为它的移动构造函数已被隐式删除。

假设我们有一个 class X.

struct X
{
    X(const X&) = delete; // user-declared

    X(int)
    {
    }
};

现在,如果你要写

X x = 4;

相同
X x = X(4); // copy/move into x, see 15.6.1

你会得到一个 compilation error 因为你显式删除了复制构造函数,因此没有隐式声明移动构造函数。

15.8.1 Copy/move constructors

[...]

If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator, and
  • X does not have a user-declared destructor.

[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]

在 C++17 中,随着保证 copy elision.
的引入,这种情况发生了变化 这导致该行等于

X x(4);

它不依赖于复制或移动构造函数而是调用 X(int).

X一样,std::atomic也明确删除了它的复制构造函数 这就是为什么如果不使用 C++17 支持编译代码将无法编译的原因。