Fundamental issues

Clause 1: Carefully distinguish Pointers and references

  • The first thing you need to realize is that there is no such thing as a null Reference.
  • Since reference must represent an object, C++ therefore requires references to have an initial value.
  • Another important difference between Pointers and References is that whereas references can be reassigned to another object, references always refer to the object they originally acquired.
  • Conclusion: References should be used when you know you need to point to something and will never change to point to something else, or when you implement an operator whose syntax requirements cannot be met by Pointers. At any other time, use Pointers.

Clause 2: it is best to use the C++ transformation operator

  • C++ offers four new transition operators, although the syntax looks long and stinky compared to c-style transitions. But it offers rigorous meaning and greater recognition.
  • If you use the new transformation method in your program, it is easier to parse (both for humans and tools), and the compiler can therefore diagnose transformation errors that the old transformation method cannot detect.
  • Making transitions ugly and hard to type might be a good thing.

Article 3: Never treat arrays as polymorphic

  • Because the base and derived classes have different sizes, the result of iterating through the base array is unpredictable if the parameters are an array of the base class and the arguments are an array of the derived class.
  • Simply put, polymorphism and pointer arithmetic should not be mixed. Array objects are almost always designed for pointer arithmetic, so do not mix array and polymorphism.

Clause 4: Do not provide Default constructor when it is not necessary

class EquipmentPiece {
public:
  EquipmentPiece(intIDNumber = UNSPECIFIED); .private:
  static const int UNSPECIFIED;  // A number means that no ID value is specified.};Copy the code
  • This is a class with the addition of Default Constructor, so that we can directly pass this class

EquipmentPiece e; Such a statement produces an object of a EquipmentPiece. While convenient to use, this almost always complicates other Member functions within the class.

  • Adding meaningless Default constructor will affect the efficiency of classes. If member Functions must test whether a field (referred to as a required field for default constructor with a default value assigned to it) has actually been initialized, its caller must pay the time cost of testing the behavior, and the space cost of testing the code, because the executable file and library are larger. If the test results are negative, the corresponding processing costs some space. If class Constructors can ensure that all the fields of an object are initialized correctly, all of the above costs can be eliminated. If Default Constructor fails to provide this assurance, then it is best to avoid default Constructor. While this may impose some restrictions on how classes can be used, it also comes with some guarantees: when you do use such classes, you can expect the objects they produce to be fully initialized and actually efficient.

The operator

Clause 5: Be wary of custom “type conversion functions.

  • Single-argument constructors and implicit type conversion operators allow custom type arguments to be implicitly converted.
  • Overloading the type conversion operator may cause an incorrect (and unexpected) function to be called. The solution is to replace the overloaded conversion operator (refer to c_str of STD ::string) with a functional equivalent.
  • Declare constructors explicit so that the compiler cannot call them for implicit conversions, only for display calls. In this way, implicit conversions caused by single argument constructors can be eliminated.

Clause 6: Distinguish between the pre and post forms of the Increment/Decrement operator

  • Overloaded normal form of increment pre-and post-operators (same for Decrement) :
// Increment and fetch;
UPInt& UPInt::operator+ + () {*this+ =1;
return *this;
}
// Select * from t1 where t1 = 1;
const UPInt UPInt::operator+ + (int)
{
UPInt oldValue = *this; + + (*this);
return oldValue;
}
Copy the code
  • In order to make calls like I ++++ illegal, the return value of the overloaded increment operator must be const.
  • The post-retirement increment and Decrement operators should be implemented on the basis of their pre-retirement Cousins. This way you only need to maintain the front-loaded version.
  • Since the postretirement increment (Decrement) function returns a temporary object, it is inherently less efficient than its predecessor (mainly for custom types).

Clause 7: don’t overload, &&, | |, and operators

  • C++ uses what is called a “sudden death” evaluation of true and false expressions. This means that once the true or false value of the expression is determined, the evaluation is complete even if there are parts of the expression that have not been tested.
  • And if the reloading the && and | | operators are they became a function call, the function call is unable to achieve a similar “sudden death” grammar, because the function call must be finished all parameter evaluation. There is also no guarantee of the order in which expressions are evaluated because the C++ language specification does not explicitly define the order in which parameters in a function call action are evaluated.
  • The comma operator has a similar problem. If the expression contains a comma, the left side of the comma is evaluated first, and then the right side of the comma is evaluated again; Finally, the result of the entire comma expression is represented by the value to the right of the comma. If you override it, you can’t mimic these behaviors.

Understand the different meanings of new and delete

  • If you want to generate objects from the heap, use new Operator. It not only allocates memory but calls a constructor for the object. If you simply intend to allocate memory, call operator New and no constructor will be called. Write your own operator new and use new operator. It will automatically call the operator new you wrote when the heap Objects are generated. If you intend to construct objects in memory that has been allocated (and has Pointers), use Placement New.
  • The relationship is summarized as follows:
New <->delete operator new <-> operator delete // Allocate, release memory placement new <-> placement delete // Construct, delete object new[] <-> delete[]Copy the code
  • Example operator new call:
void *rawMemroy = operator new(sizeof(string));
Copy the code
  • Plcement New Demonstration:
class Widget {
public:
  Widget(intwidgetSize); . };Widget* constructWidgetInBuffer(void* buffer, int widgetSize)
{
  return new (buffer) Widget(widgetSize);
}
Copy the code