我不明白为什么我会这样做:
struct S {
int a;
S(int aa) : a(aa) {}
S() = default;
};
Run Code Online (Sandbox Code Playgroud)
为什么不说:
S() {} // instead of S() = default;
Run Code Online (Sandbox Code Playgroud)
为什么要为此引入一个新关键字?
我最近注意到C++ 0x中的一个类需要一个显式的默认构造函数.但是,我没有想出一个可以隐式调用默认构造函数的场景.这似乎是一个相当无意义的说明者.我想也许它会Class c;不赞成,Class c = Class();但似乎并非如此.
来自C++ 0x FCD的一些相关引用,因为我更容易导航[类似文本存在于C++ 03中,如果不在同一个地方]
12.3.1.3 [class.conv.ctor]
默认构造函数可以是显式构造函数; 这样的构造函数将用于执行默认初始化或值初始化(8.5).
它继续提供显式默认构造函数的示例,但它只是模仿我上面提供的示例.
8.5.6 [decl.init]
默认初始化T类型的对象意味着:
- 如果T是一个(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
8.5.7 [decl.init]
对值类型T的对象进行值初始化意味着:
- 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
在这两种情况下,标准都要求调用默认构造函数.但是如果默认构造函数是非显式的,那就会发生这种情况.为了完整起见:
8.5.11 [decl.init]
如果没有为对象指定初始化程序,则默认初始化该对象;
据我所知,这只是从没有数据的转换.这没有意义.我能想到的最好的是以下内容:
void function(Class c);
int main() {
function(); //implicitly convert from no parameter to a single parameter
}
Run Code Online (Sandbox Code Playgroud)
但显然这不是C++处理默认参数的方式.还有什么会使explicit Class();行为与众不同Class();?
生成此问题的具体示例是std::function[20.8.14.2 func.wrap.func].它需要几个转换构造函数,其中没有一个被标记为显式,但默认构造函数是.
定义类时,现在通常= default用于析构函数/复制构造函数和复制赋值。查看我的代码库,这些几乎总是只在头文件中,但有些同事已将它们放在.cpp文件中。在这种情况下,最佳做法是什么?
编译器是否在标头中多次生成这些函数并依靠链接器对它们进行重复数据删除。.cpp如果你有一个很大的班级,也许只值得把它们放在文件中?对于我们大部分是旧的 C++98 代码,什么都不做的函数通常也只在头文件中定义。什么都不做虚拟析构函数似乎经常被移动到.cpp文件中。对于需要它们的地址来填充虚拟方法表的虚拟方法来说,它是否(或曾经)在某种程度上很重要。
还建议noexcept()在= default函数上放置子句吗?编译器似乎是自己派生的,因此它仅在存在时用作 API 文档。
在C++17中,考虑这样一种情况:S一个结构体删除了默认构造函数,并且有一个float成员,当S用空大括号初始化时,标准是否保证float成员被零初始化?
struct A {
int x{};
};
struct S
{
S() = delete;
A a;
float b;
};
int main()
{
auto s = S{}; // Is s.b guaranteed to be zero?
}
Run Code Online (Sandbox Code Playgroud)
在我看来,cppreference.com 并不清楚,都说:
如果初始值设定项子句的数量小于成员的数量且基数或初始值设定项列表完全为空,则剩余的成员和基数 (C++17 起) 将由其默认成员初始值设定项(如果在类定义中提供)进行初始化,否则(C++14 起) 根据通常的列表初始化规则,从空列表进行复制初始化(对具有默认构造函数的非类类型和非聚合类执行值初始化,并对聚合执行聚合初始化)。如果引用类型的成员是这些剩余成员之一,则程序格式错误。
(来自这里),这意味着 b 保证为零
在所有情况下,如果使用空大括号对 {} 并且 T 是聚合类型,则执行聚合初始化而不是值初始化。
(从这里)
这意味着 b 不能保证为零。
还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器都会进行零初始化:
该标准指定,当类具有用户提供或删除的默认构造函数时,不会执行零初始化,即使重载决策未选择该默认构造函数也是如此。如果选择了未删除的默认默认构造函数,所有已知的编译器都会执行额外的零初始化。
简而言之,为什么下面的代码表现得像评论中描述的那样?
struct A
{
A() = delete;
//A(const A&) {} // uncommenting this...
};
int main()
{
A a{}; // ... breaks this
//A(); // this fails in either case because of `A() = delete;` only
}
Run Code Online (Sandbox Code Playgroud)
我应该查看标准的哪一部分(或至少是 cppreference 上的一页)来理解这一点?
但是,写入A(const A&) = default;而不是//A(const A&) {} 不会中断A a{};。那这个呢?我认为根本原因是相同的,但是真正了解 C++ 的人的一句话比我认为的要好。
c++ default-constructor language-lawyer value-initialization c++11
我从cppreference发现了这个例子:
\n...\n\nstruct T3\n{\n int mem1;\n std::string mem2;\n T3() {} // user-provided default constructor\n}\n\n...\nRun Code Online (Sandbox Code Playgroud)\n此示例清楚地表明给定的构造函数是用户提供的构造函数,因为它在第一个声明中没有显式默认或删除;根据 [dcl.fct.def.default]/5:
\n\n\n[..] 如果函数是用户声明的并且在其第一次声明时未\n显式默认或删除,则该函数是用户提供的 [..]
\n
现在,根据 [dcl.init.aggr]/1
\n\n\n聚合是一个数组或一个类(第 11 条)
\n\n
\n- (1.1) \xe2\x80\x94 没有用户声明或继承的构造函数 (11.4.5),
\n- (1.2) \xe2\x80\x94 没有私有或受保护的直接非静态数据成员 (11.8),
\n- (1.3) \xe2\x80\x94 无虚函数 (11.7.3),以及
\n- (1.4) \xe2\x80\x94 无虚拟、私有或受保护的基类 (11.7.2)。
\n
看来我的类满足上述所有要求,成为一个聚合,包括点 (1.1),因为给定的构造函数不是用户声明的。
\n那么为什么下面的代码格式错误(在带有 c++20 标志的 g++12.2 上测试):
\nstatic_assert(std::is_aggregate<T3>::value); // fail\nRun Code Online (Sandbox Code Playgroud)\n为什么静态断言失败?
\n根据这个网站/链接/:
如果显式声明默认构造函数但将其标记为已删除,则不能使用空大括号初始化:
它还给出了一个例子:
class class_f {
public:
class_f() = delete;
class_f(string x): m_string { x } {} // if it is deleted, there will be no errors.
string m_string;
};
int main()
{
class_f cf{ "hello" };
class_f cf1{}; // compiler error C2280: attempting to reference a deleted function
}
Run Code Online (Sandbox Code Playgroud)
我真正不明白的是,如果没有用户提供的构造函数,即使删除的默认构造函数仍然存在,也不会再出现错误。据我所知,如果有用户提供的构造函数,就不会存在隐式的默认构造函数,但默认构造函数已经被删除了。所以我不知道在值初始化的情况下调用什么以及为什么它在下面的示例中起作用:
#include <string>
class class_f {
public:
class_f() = delete;
std::string m_string;
};
int main()
{
class_f cf1{}; // Does the implicit-default constructor is called here? But, it …Run Code Online (Sandbox Code Playgroud) 这可能不是 C++20 特有的,但这就是我现在正在使用的。我有一个简单的结构
\nstruct foo {\n int bar;\n}\nRun Code Online (Sandbox Code Playgroud)\n可以声明并初始化为
\nconst auto baz = foo{42};\nRun Code Online (Sandbox Code Playgroud)\n现在,当我禁用移动构造函数 ( foo(foo&&) = delete;) 时,上述初始化失败并显示
\n\n错误:没有匹配的函数可调用 \xe2\x80\x98foo::foo()\xe2\x80\x99
\n
出现此错误的原因是什么?有没有办法恢复默认行为?
\n