Can I apply the last keyword to a POD (standard-layout) structure in C ++ 11? Do I need to?

In a C ++ project that is filled with objects (with proper behavior) and a relatively small number of non-object-oriented structures (consisting of only data fields and no methods), I would like to prevent accidental abuse of these structures, in which you can try to create a class inheriting from it.

According to my understanding, since these "POD" structures (plain old data) do not have a virtual destructor, it is impossible to correctly remove the object of the derived class (if it can be created) using the pointer type POD.

This seems to be well suited for the C ++ 11 final keyword, which marks a class or structure as non-inherited.

However, I wonder if the keyword β€œfinal” arises so that the structure becomes a non-POD?

I suspect that the standards documentation may solve this problem, but I'm not smart enough to sift through very long documents to figure them out. Any useful pointers would be appreciated.

Note. I'm not interested in just knowing that it passes compilation of some compiler providers. Passing the compilation does not guarantee:

  • Will the compiled code execute correctly in all situations (especially when the technique is used in a larger and more complex project),
  • Is this supposed to be used by the C ++ standards body in this way.
#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; } 
+6
source share
2 answers

According to my understanding, since these "POD" structures (plain old data) do not have a virtual destructor, it is impossible to correctly remove the object of the derived class (if it can be created) using the pointer type POD.

It is not possible to specify a raw pointer, but you can get a smart pointer object, such as std::shared_ptr or std::unique_ptr with the corresponding deleter.

Since smart pointers have been standardized, there are a few excuses that should be continued after poor practice using the delete operator manually. Of course, classes should not be designed to be compatible with the delete operator. Each class interface must be designed with its use in mind.

No, it is not a good practice to make each class either final or polymorphic.

However, I wonder if the keyword β€œfinal” arises so that the structure becomes a non-POD?

No, it's still a POD. POD requirements are a standard layout (which in turn does not require a base class, access specifiers between members, nothing virtual) and trivial special member functions (copy / move constructor, assignment operator, destructor).

However, the goal of POD-ness is to allow you to use memcpy instead of properly assembling objects that good C ++ code would have avoided doing.

+4
source

The marking of the final class does not change the status of the POD. Citation C ++ 11:

9 [class]:

6 A trivially copied class is a class that:

  • does not have non-trivial copy constructors (12.8),
  • has no non-trivial displacement constructors (12.8),
  • no nontrivial copy assignment operators (13.5.3, 12.8),
  • has no non-trivial displacement 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 can be trivially copied. [Note: in particular, a trivially copied or trivial class does not have virtual functions or a virtual base class.-end note]

7 The standard layout class is a class that:

  • does not have non-static data members such as a non-standard class layout (or an array of such types) or a link,
  • does not have virtual functions (10.3) and there are no virtual base classes (10.1),
  • has the same access control (section 11) for all non-static data members,
  • does not have base classes of non-standard layout,
  • either does not have non-static data members in the derived class and no more than one base class with non-static data elements or does not have base classes with non-static data elements and
  • does not have base classes of the same type as the first non-static data element.

8 The standard layout structure is the standard layout class defined using the key of the struct class or the key of the class class ....

10 The POD structure is a non-unit class, which is a trivial class and a standard layout class, and does not have non-static data members such as non-POD struct, non-POD union (or an array of such types) ....

12.1 [class.ctor]

5 ... The default constructor is trivial if it is not provided by the user, and if:

  • its class has no virtual functions (10.3) and there are no virtual base classes (10.1) and
  • there is no non-static data element of its class that has parenthesis initializer or equal, and
  • all direct base classes of its class have trivial default constructors, and
  • for all non-static data members of its class that belong to the class type (or its array), each such class has a trivial default constructor.

Otherwise, the default constructor is nontrivial.

12.4 [class.dtor]

5 ... The destructor is trivial if it is not provided to the user, and if:

  • the destructor is not virtual,
  • all direct base classes of its class have trivial destructors, and
  • for all non-static data members of its class that belong to the class type (or its array), each of these classes has a trivial destructor.

Otherwise, the destructor is not trivial.

12.8 [class.copy]

12 The copy / move constructor for class X is trivial if it is not provided by the user and if - the class X does not have virtual functions (10.3) and virtual base classes (10.1) and - the constructor selected for copy / move each subobject of the direct base class is trivial and - for each non-static data element X , which refers to the class type (or its array), the selected constructor for copying / moving this element is trivial;

otherwise, the copy / move constructor is not trivial.

25 The copy / move assignment operator for class X is trivial if not provided by the user and if

  • class X has no virtual functions (10.3) and virtual base classes (10.1) and
  • the assignment operator selected to copy / move each subobject of the direct base class is trivial and
  • for each non-static data element X that belongs to the class type (or its array), the assignment operator selected for copying / moving this element is trivial,

otherwise the copy / move assignment operator is nontrivial.

As you can see, the definition of the POD structure does not take into account whether the class has a class-virt-t final .

+1
source

All Articles