我已经删除了所有的构造函数,即使下面的代码运行良好。如何以及为什么?
class Ax
{
public:
Ax() = delete;
Ax(Ax const&)=delete;
Ax(Ax&&)=delete;
void operator=(Ax const&)=delete;
void operator=(Ax&&)=delete;
void print()
{
cout << "Hello \n";
}
};
int main(int argc, char** argv)
{
Ax{}.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
dfr*_*fri 43
类Ax
是在C ++ 11,C ++ 14和C ++ 17的聚集体,因为它没有用户提供的构造,这意味着Ax{}
是集合初始化,绕过任何用户声明的构造,即使是删除的。
struct NonConstructible {
NonConstructible() = delete;
NonConstructible(const NonConstructible&) = delete;
NonConstructible(NonConstructible&&) = delete;
};
int main() {
//NonConstructible nc; // error: call to deleted constructor
// Aggregate initialization (and thus accepted) in
// C++11, C++14 and C++17.
// Rejected in C++20 (error: call to deleted constructor).
NonConstructible nc{};
}
Run Code Online (Sandbox Code Playgroud)
什么是聚合类的定义在各种标准版本(C++11 到 C++20)中发生了变化,这些规则可能会产生一些令人惊讶的结果。从 C++20 开始,特别是由于
大多数经常令人惊讶的聚合行为已得到解决,特别是不再允许聚合具有用户声明的构造函数,这是对类作为聚合的更严格要求,而不仅仅是禁止用户提供的构造函数。
请注意,提供一个显式默认(或删除)的外部定义算作用户提供的构造函数,这意味着在以下示例中,B
具有用户提供的默认构造函数,而A
没有:
struct A {
A() = default; // not user-provided.
int a;
};
struct B {
B(); // user-provided.
int b;
};
// Out of line definition: a user-provided
// explicitly-defaulted constructor.
B::B() = default;
Run Code Online (Sandbox Code Playgroud)
结果A
是聚合,而B
不是。反过来,这B
意味着通过空的direct-list-init 初始化将导致其数据成员b
处于未初始化状态。A
但是,对于,相同的初始化语法将导致(通过A
对象的聚合初始化和其数据成员 a 的后续值初始化)其数据成员的零初始化a
:
A a{};
// Empty brace direct-list-init:
// -> A has no user-provided constructor
// -> aggregate initialization
// -> data member 'a' is value-initialized
// -> data member 'a' is zero-initialized
B b{};
// Empty brace direct-list-init:
// -> B has a user-provided constructor
// -> value-initialization
// -> default-initialization
// -> the explicitly-defaulted constructor will
// not initialize the data member 'b'
// -> data member 'b' is left in an unititialized state
Run Code Online (Sandbox Code Playgroud)
这可能会让人感到意外,并且存在读取未初始化数据成员b
并导致未定义行为的明显风险:
A a{};
B b{}; // may appear as a sound and complete initialization of 'b'.
a.a = b.b; // reading uninitialized 'b.b': undefined behaviour.
Run Code Online (Sandbox Code Playgroud)
N. *_*ead 12
在 C++17 中,您的示例是一个聚合。对于 C++17 聚合只需要没有用户提供的构造函数;用户声明(但明确删除或默认)的构造函数很好。
在这种情况下,当你执行聚合初始化时Ax{}
,它不会调用任何构造函数......包括删除的构造函数,因此编译。
在 C++20 中,规则已更改,因此任何用户声明的构造函数都会阻止该类型成为聚合,因此该示例将无法编译。
另见https://en.cppreference.com/w/cpp/language/aggregate_initialization