我可以将 final 关键字应用于 C++11 中的 POD(标准布局)结构吗?我是不是该?
Can I apply the final keyword to a POD (standard-layout) struct in C++11 ? Should I?
在一个充满对象(具有正确行为)和相对较少的非面向对象结构(仅由数据字段和无方法组成)的 C++ 项目中,我想防止意外误用这些结构,其中可能会尝试创建一个继承自它的 class。
据我了解,因为这些 "POD"(普通旧数据)结构没有虚拟析构函数,所以无法正确删除派生的 class 对象(如果允许的话)通过 POD 类型的指针创建它。
这似乎是 C++11 "final" 关键字的一个很好的用例,它将 class 或结构标记为不可继承。
但是,我想知道 "final" 关键字是否导致结构成为非 POD?
我怀疑标准文档可能已经解决了这个问题,但我不够聪明,无法在很长的文档中进行筛选以找出答案。欢迎任何有用的指点。
注意:我对仅仅知道它通过了某些编译器供应商的编译不感兴趣。通过编译不保证:
- 编译后的代码是否在所有情况下都能正确执行(尤其是当该技术应用于更大、更复杂的项目时),
- C++ 标准机构是否打算以这种方式使用它。
#include <iostream>
using namespace std;
struct Pod final
{
int a;
int b;
int c;
};
#if 0
class FailsBecauseCannotDeriveFromFinalAnything : public Pod
{
};
#endif
class ContainsSomethingFinalAsMember
{
public:
ContainsSomethingFinalAsMember() : pod() {}
private:
Pod pod;
};
int main()
{
std::cout << std::is_pod < Pod > :: value << std::endl;
return 0;
}
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
给定原始指针是不可能的,但给定智能指针对象是可能的,例如 std::shared_ptr
或带有适当删除器的 std::unique_ptr
。
自从智能指针被标准化后,就没有理由继续遵循手动使用 delete
运算符的不良做法。当然,classes 不应围绕与 delete
运算符的兼容性而设计。每个 class 界面在设计时都应考虑到其特定用途。
不,让每个 class 成为 final
或多态性都不是一个好习惯。
However, I wonder if the "final" keyword causes the struct to become non-POD?
不,它仍然是 POD。 POD 的要求是标准布局(反过来不需要基数 class、成员之间没有访问说明符、没有虚拟任何东西)和简单的特殊成员函数(copy/move 构造函数、赋值运算符、析构函数)。
但是,POD-ness 的目的是允许您使用 memcpy
而不是正确构造对象,好的 C++ 代码会避免这样做。
标记 class final
不会更改其 POD 状态。引用 C++11:
9 [class]:
6 A trivially copyable class is a class that:
- has no non-trivial copy constructors (12.8),
- has no non-trivial move constructors (12.8),
- has no non-trivial copy assignment operators (13.5.3, 12.8),
- has no non-trivial move assignment operators (13.5.3, 12.8), and
- has a trivial destructor (12.4).
A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base
classes.—end note ]
7 A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with
non-static data members, or has no base classes with non-static data members, and
- has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key struct
or the class-key class
. ...
10 A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no
non-static data members of type non-POD struct, non-POD union (or array of such types). ...
12.1 [class.ctor]
5 ... A default constructor is trivial if it is not user-provided and if:
- its class has no virtual functions (10.3) and no virtual base classes (10.1), and
- no non-static data member of its class has a brace-or-equal-initializer, and
- all the direct base classes of its class have trivial default constructors, and
- for all the non-static data members of its class that are of class type (or array thereof), each such class
has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
12.4 [class.dtor]
5 ... A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type (or array thereof), each such
class has a trivial destructor.
Otherwise, the destructor is non-trivial.
12.8 [class.copy]
12 A copy/move constructor for class X
is trivial if it is not user-provided and if
— class X
has no virtual functions (10.3) and no virtual base classes (10.1), and
— the constructor selected to copy/move each direct base class subobject is trivial, and
— for each non-static data member of X
that is of class type (or array thereof), the constructor selected
to copy/move that member is trivial;
otherwise the copy/move constructor is non-trivial.
25 A copy/move assignment operator for class X
is trivial if it is not user-provided and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and
- the assignment operator selected to copy/move each direct base class subobject is trivial, and
- for each non-static data member of
X
that is of class type (or array thereof), the assignment operator
selected to copy/move that member is trivial;
otherwise the copy/move assignment operator is non-trivial.
如您所见,POD 结构的定义没有考虑 class 是否具有 class-virt-specifier final
.
在一个充满对象(具有正确行为)和相对较少的非面向对象结构(仅由数据字段和无方法组成)的 C++ 项目中,我想防止意外误用这些结构,其中可能会尝试创建一个继承自它的 class。
据我了解,因为这些 "POD"(普通旧数据)结构没有虚拟析构函数,所以无法正确删除派生的 class 对象(如果允许的话)通过 POD 类型的指针创建它。
这似乎是 C++11 "final" 关键字的一个很好的用例,它将 class 或结构标记为不可继承。
但是,我想知道 "final" 关键字是否导致结构成为非 POD?
我怀疑标准文档可能已经解决了这个问题,但我不够聪明,无法在很长的文档中进行筛选以找出答案。欢迎任何有用的指点。
注意:我对仅仅知道它通过了某些编译器供应商的编译不感兴趣。通过编译不保证:
- 编译后的代码是否在所有情况下都能正确执行(尤其是当该技术应用于更大、更复杂的项目时),
- C++ 标准机构是否打算以这种方式使用它。
#include <iostream>
using namespace std;
struct Pod final
{
int a;
int b;
int c;
};
#if 0
class FailsBecauseCannotDeriveFromFinalAnything : public Pod
{
};
#endif
class ContainsSomethingFinalAsMember
{
public:
ContainsSomethingFinalAsMember() : pod() {}
private:
Pod pod;
};
int main()
{
std::cout << std::is_pod < Pod > :: value << std::endl;
return 0;
}
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
给定原始指针是不可能的,但给定智能指针对象是可能的,例如 std::shared_ptr
或带有适当删除器的 std::unique_ptr
。
自从智能指针被标准化后,就没有理由继续遵循手动使用 delete
运算符的不良做法。当然,classes 不应围绕与 delete
运算符的兼容性而设计。每个 class 界面在设计时都应考虑到其特定用途。
不,让每个 class 成为 final
或多态性都不是一个好习惯。
However, I wonder if the "final" keyword causes the struct to become non-POD?
不,它仍然是 POD。 POD 的要求是标准布局(反过来不需要基数 class、成员之间没有访问说明符、没有虚拟任何东西)和简单的特殊成员函数(copy/move 构造函数、赋值运算符、析构函数)。
但是,POD-ness 的目的是允许您使用 memcpy
而不是正确构造对象,好的 C++ 代码会避免这样做。
标记 class final
不会更改其 POD 状态。引用 C++11:
9 [class]:
6 A trivially copyable class is a class that:
- has no non-trivial copy constructors (12.8),
- has no non-trivial move constructors (12.8),
- has no non-trivial copy assignment operators (13.5.3, 12.8),
- has no non-trivial move assignment operators (13.5.3, 12.8), and
- has a trivial destructor (12.4).
A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable. [ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base classes.—end note ]
7 A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
- has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key
struct
or the class-keyclass
. ...10 A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). ...
12.1 [class.ctor]
5 ... A default constructor is trivial if it is not user-provided and if:
- its class has no virtual functions (10.3) and no virtual base classes (10.1), and
- no non-static data member of its class has a brace-or-equal-initializer, and
- all the direct base classes of its class have trivial default constructors, and
- for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
12.4 [class.dtor]
5 ... A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor is non-trivial.
12.8 [class.copy]
12 A copy/move constructor for class
X
is trivial if it is not user-provided and if — classX
has no virtual functions (10.3) and no virtual base classes (10.1), and — the constructor selected to copy/move each direct base class subobject is trivial, and — for each non-static data member ofX
that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;otherwise the copy/move constructor is non-trivial.
25 A copy/move assignment operator for class
X
is trivial if it is not user-provided and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and- the assignment operator selected to copy/move each direct base class subobject is trivial, and
- for each non-static data member of
X
that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;otherwise the copy/move assignment operator is non-trivial.
如您所见,POD 结构的定义没有考虑 class 是否具有 class-virt-specifier final
.