值初始化是否调用隐式默认构造函数?C++初始化规则疑问
关于C++空大括号初始化与删除默认构造函数的疑问
问题背景
根据微软文档说明:
若默认构造函数被显式声明且标记为deleted,则无法使用空大括号初始化。
文档给出的报错示例:
#include <string> using namespace std; class class_f { public: class_f() = delete; class_f(string x): m_string { x } {} // 若删除此构造函数则无错误 string m_string; }; int main() { class_f cf{ "hello" }; class_f cf1{}; // 编译器错误C2280:尝试引用已删除的函数 }
但实际测试发现一个矛盾场景:当类中没有用户提供的构造函数时,即使显式删除了默认构造函数,空大括号初始化仍能正常运行。比如以下代码无编译错误:
#include <string> class class_f { public: class_f() = delete; std::string m_string; }; int main() { class_f cf1{}; // 此处为何不会触发已删除函数的调用错误? }
问题解答
核心差异在于类是否属于聚合类型,这直接决定了空大括号初始化的行为逻辑:
1. 第一个示例报错的原因
当类中存在用户自定义的构造函数(比如class_f(string x))时,该类不再是聚合类型。此时class_f cf1{}属于值初始化,编译器会尝试调用类的默认构造函数,但你已经显式删除了这个函数,因此触发C2280错误。
2. 第二个示例正常运行的原因
第二个类中没有用户提供的构造函数(注意:class_f() = delete属于显式删除声明,不算用户提供的自定义构造函数),因此它是聚合类型。对于聚合类型,空大括号初始化走的是聚合初始化逻辑:
- 聚合初始化会逐个初始化类的成员变量,这里会对
m_string执行值初始化(即调用std::string的默认构造函数); - 整个过程完全不会尝试调用被删除的
class_f默认构造函数,因此不会触发错误。
补充:C++标准规定,仅当类包含用户提供的构造函数时,才会失去聚合类型的属性。显式删除默认构造函数的操作,不会改变类的聚合类型属性。
内容的提问来源于stack exchange,提问作者Fox1942
相关产品推荐
相关产品推荐

