[email protected] A literary creation from the beginning ,C...">

当前位置:网站首页>Tips for this week 131: special member functions and ` = Default`

Tips for this week 131: special member functions and ` = Default`

2022-07-07 17:57:00 -Flying crane-

As totw#131 Originally published in 2017 year 3 month 24 Japan

from James Dennett ([email protected]) A literary creation

from the beginning ,C++ It supports the compiler declaration version of some so-called special member functions : Default constructor 、 Destructor 、 Copy constructor and copy assignment operator . C++11 Added move construction and move assignment to the list , And added syntax (=default and =delete) To control when these default values are declared and defined .

=default What's the role , Why do we use it ?

Write =default We tell the compiler “ What you usually do for this special member function ” The way . Why should we do this instead of writing the implementation manually or having the compiler declare one for us ?

  • We can change the access level ( for example , Make constructors protected rather than public ), Make the destructor virtual , Or restore the function that will be suppressed ( for example , Default constructor for classes with other user declared constructors ) And still Let the compiler generate functions for us .
  • If you copy / Moving members is enough , Compiler defined copy and move operations do not need to be maintained every time members are added or deleted .
  • The special member functions provided by the compiler can be unimportant ( When all the operations they call on themselves are unimportant ), This can make them faster 、 More secure .
  • Types with default constructors can be aggregated , Therefore, aggregation initialization is supported , Types with user supplied constructors cannot .
  • Explicitly declaring a default member provides us with a place , Used to record the semantics of the result function .
  • In class templates ,=default It's a simple way , To conditionally declare operations , It depends on whether some basic types provide it .

When we use =default when , The compiler will check whether it can synthesize inline definitions for this function . If possible , It just goes on . If not , This function is actually declared deleted , Like we wrote =delete equally . This is exactly what we need to transparently wrap classes ( for example , If we are defining a class template ), But readers may be surprised .

If the initial declaration of the function uses =default, Or if the compiler declares a special member function that is not declared by the user , Will derive the appropriate noexcept standard , This may allow faster code .

How does it work ?

stay C++11 Before , If we need a default constructor or have other constructors , So we can write like this :

class A {
    
 public:
  A() {
    }  // User-provided, non-trivial constructor makes A a non-aggregate.
};

from C++11 At first we have more choices :

class C {
    
 public:
  C() = default;  // misleading: C has a deleted default constructor
 private:
  const int i;  // const => must always be initialized.
};

class D {
    
 public:
  D() = default;  // unsurprising, but not explicit: D has a default constructor
 private:
  std::unique_ptr<int> p;  // std::unique_ptr has a default constructor
};

obviously , We should not write classes C Code like that : In non template , Only if you want this class to support this operation ( Then test whether it supports ) Use only when =default. clang-tidy Including the inspection of this .

After the first declaration of a special member function ( That is, outside the class ) Use =default when , It has a simpler meaning : It tells the compiler to define functions , And give an error when it is impossible to do so . When used outside the class =default when , The default function will not be trivial : Trivial is determined by the first statement ( So all clients agree whether the operation is trivial ).

If you don't need your class to be an aggregate and you don't need a constructor, it's trivial , Then the default constructor outside the class definition , Consider the following example E and F, It's usually a good choice . Its meaning is clear to readers , And checked by the compiler . For special cases of default constructors or destructors , We can write {} instead of =default, But for other default operations , Compiler generated implementations are not so simple , For consistency , It is best to write in all applicable cases =default.

class E {
    
 public:
  E();  // promises to have a default constructor, but...
 private:
  const int i;  // const => must always be initialized.
};
inline E::E() = default;  // compilation error here: would not initialize `i`

class F {
    
 public:
  F();  // promises to have a default constructor
 private:
  std::unique_ptr<int> p;  // std::unique_ptr has a default constructor
};
inline F::F() = default;  // works as expected

Suggest

first =default Instead of writing an equivalent implementation manually , Even if the implementation is just {}. Optionally , Omit from the initial declaration =default And provide a separate default implementation .

Note the default move operation . Objects from mobile still have to satisfy the invariants of their types , And the default implementation usually does not preserve the relationship between fields .

Outside the template , If =default No implementation provided , Use the =delete.

原网站

版权声明
本文为[-Flying crane-]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071522592339.html