默认析构函数有什么用?
What are defaulted destructors used for?
我可以理解默认构造函数,因为用户定义的构造函数将禁用编译器生成的构造函数,使对象不可平凡复制等。
在析构函数的情况下,除了更改访问类别之外,考虑到没有用户定义的成员函数可以禁用它们(无论如何都不能重载析构函数),定义默认析构函数有什么用?
// Which version should I choose ?
struct Example
{
//1. ~Example() = default;
//2. ~Example() {}
//3.
};
即使在虚拟析构函数的情况下,默认它们也不会使它们变得微不足道,那么这样做有什么好处呢?
基本上它是关于传达意图,但相当多余。
但如果您使用 std::unique_ptr
作为 class 的成员,则需要在 header 中声明析构函数(但仅声明)。然后你可以让它在源文件中使用默认实现,如下所示:
MyClass:~MyClass() = default;
考虑到您的选择,我会使用第一个或第三个。
微不足道的析构函数遗漏的例外与 derived class' 析构函数有关,而不是基础析构函数。所以 virtual ~Foo() = default;
是保留默认析构函数但将其虚拟化的有用构造。
正如 Nikos Athanasiou 在评论中提到的,默认构造函数使类型可以轻易破坏,而用户定义的构造函数则不能。一个小代码示例将显示它:
#include <iostream>
#include <type_traits>
struct A { ~A() = default; };
struct B { ~B() {} };
struct C { ~C() noexcept {} };
int main() {
std::cout
<< std::is_trivially_destructible<A>::value
<< std::is_trivially_destructible<B>::value
<< std::is_trivially_destructible<C>::value
<< std::endl;
return 0;
}
显示器
100
至于虚拟析构函数,与非虚拟析构函数的一致性和Quentin的回答是适当的理由。我的个人建议是尽可能使用默认值,因为这是坚持最规范行为的一种方式。
一个用途是使析构函数 protected
或 private
同时可能保持 class 微不足道:只需将其列在所需的访问说明符之后。
另:在编写classes时,一些程序员喜欢对class的函数进行排序:例如构造函数,然后是析构函数,然后是非 const
"mutating" 成员,然后是 const
"accessor" 成员,然后是 static
函数。通过能够显式 = default
析构函数,您可以按预期的顺序列出它,并且 reader 看那里就知道不会有另一个放错地方的版本。在大型 classes 中,它可能有一些 documentary/safety 值。
它也给了你一些具体的东西来添加注释,这可以帮助一些文档工具实现注释与销毁相关。
我可以理解默认构造函数,因为用户定义的构造函数将禁用编译器生成的构造函数,使对象不可平凡复制等。
在析构函数的情况下,除了更改访问类别之外,考虑到没有用户定义的成员函数可以禁用它们(无论如何都不能重载析构函数),定义默认析构函数有什么用?
// Which version should I choose ?
struct Example
{
//1. ~Example() = default;
//2. ~Example() {}
//3.
};
即使在虚拟析构函数的情况下,默认它们也不会使它们变得微不足道,那么这样做有什么好处呢?
基本上它是关于传达意图,但相当多余。
但如果您使用 std::unique_ptr
作为 class 的成员,则需要在 header 中声明析构函数(但仅声明)。然后你可以让它在源文件中使用默认实现,如下所示:
MyClass:~MyClass() = default;
考虑到您的选择,我会使用第一个或第三个。
微不足道的析构函数遗漏的例外与 derived class' 析构函数有关,而不是基础析构函数。所以 virtual ~Foo() = default;
是保留默认析构函数但将其虚拟化的有用构造。
正如 Nikos Athanasiou 在评论中提到的,默认构造函数使类型可以轻易破坏,而用户定义的构造函数则不能。一个小代码示例将显示它:
#include <iostream>
#include <type_traits>
struct A { ~A() = default; };
struct B { ~B() {} };
struct C { ~C() noexcept {} };
int main() {
std::cout
<< std::is_trivially_destructible<A>::value
<< std::is_trivially_destructible<B>::value
<< std::is_trivially_destructible<C>::value
<< std::endl;
return 0;
}
显示器
100
至于虚拟析构函数,与非虚拟析构函数的一致性和Quentin的回答是适当的理由。我的个人建议是尽可能使用默认值,因为这是坚持最规范行为的一种方式。
一个用途是使析构函数 protected
或 private
同时可能保持 class 微不足道:只需将其列在所需的访问说明符之后。
另:在编写classes时,一些程序员喜欢对class的函数进行排序:例如构造函数,然后是析构函数,然后是非 const
"mutating" 成员,然后是 const
"accessor" 成员,然后是 static
函数。通过能够显式 = default
析构函数,您可以按预期的顺序列出它,并且 reader 看那里就知道不会有另一个放错地方的版本。在大型 classes 中,它可能有一些 documentary/safety 值。
它也给了你一些具体的东西来添加注释,这可以帮助一些文档工具实现注释与销毁相关。