Terms 22: Consider the assignment form (op =) of the operator (OP =) (OP)
Most programmers think if they can write code this:
X = x y; x = x - y;
Then they can write this:
X = Y; X - = Y;
If x and y are user-defined type, they cannot be ensured. For C , there is no relationship between Operator , Operator = and Operator =, so if you want these three Opeerators to exist and have the relationship you expect, you must implement them yourself. Similarly, Operator -, *, /, and so on.
Make sure that Operator's assignment form (such as Operator =) is a normal relationship between a single form of Operator (such as Operator ), a good method is the latter (referring to the Operator Translator Note) Implement according to the former (referring to Operator = Translator Note) (see Terms 6). This is easy:
Class russ {
PUBLIC:
...
Rational & Operator = (Const Rational & RHS);
Rational & Operator - = (Const Rational & RHS);
}
// Operator implementation according to Operator =
// Why is the return value is Const explanation,
/ / See the implementation of the implementation of the implementation of Effective C Terms 21 and 109
Const Rational Operator (Const Rational & LHS,
Const Rational & RHS)
{
RETURN RATIONAL (LHS) = rhs;
}
// Operator - Implement according to Operator - =
Const Rational Operator- (Const Rational & LHS,
Const Rational & RHS)
{
RETURN RATIONAL (LHS) - = RHS;
}
In this example, the Operator = and - =, while Operator and Operator is to provide its own functionality by calling the aforementioned functions. Using this design method, only use the assignment form of the maintenance Operator. And if you assume that the Operator assignment is in the PUBLIC interface of the class, this does not have to make Operator's individual form of friends (see Effective C Terms 19).
If you don't mind putting all Operator's individual form in the global domain, you can use the template to replace the written form of a single form:
Template
Const t operator (Const T & lh, Const T & RHS)
{
RETURN T (LHS) = rhs; // See the discussion below}
Template
Const t operator- (Const T & lh, Const T & RHS)
{
RETURN T (LHS) - = rhs; // See the discussion below
}
...
Using these templates, as long as you define some type as you want to assign a value, once you need it, your corresponding Operator separate form is automatically generated.
This is really good, but so far, we have not considered efficiency problems, and efficiency is the theme of this chapter. It is worth pointing out that there is three efficiency issues. First, in general, the assignment of Operator is higher than its individual form, because a single form is necessary to return a new object, there is some overhead in the construction and release of the temporary object (see Terms 19 and Terms 20, and EFFECTIVE C Terms 23). The assignment of Operator writes the result to the parameters of the left, so there is no need to generate a temporary object to accommodate the return value of the Operator.
Second, it provides the form of assignment of Operator to provide its standard form, which allows the client to make a trade-off in the convenience and efficiency. In other words, the client can decide to write this:
Rational A, B, C, D, RESULT
...
Result = A B C D; / / may use 3 temporary objects
// Each Operator calls 1
Still writing:
Result = a; // No temporary object
Result = b; // No temporary object
Result = C; // No temporary object
Result = d; // No temporary object
The former is relatively easy to write, debug and maintenance, and its performance is acceptable in 80% of the time (see Terms 16). The latter has higher efficiency, which is estimated to be more intuitive for assembly language programmers. By providing two programs, you can develop and debug code with a single-form Operator that makes client developers, while reserves higher efficiency Operator assignment to replace individual forms of power. And according to the assignment form of Operator, you can ensure that the semantics of the operation can remain unchanged when the client switches from one form to another.
The last point involves the implementation of the Operator separate form. Take a look at the implementation of Operator :
Template
Const t operator (Const T & lh, Const T & RHS)
{RETURN T (LHS) = rhs;}
Expression T (LHS) calls the copy constructor of T. It creates a temporary object whose value is the same as LHS. This temporary object is used to call Operator = with RHS, and the result of the operation is returned from Operator . This code doesn't seem to write so embarrassment. Is this not better?
Template
Const t operator (Const T & lHS, Const T & r Hs) {
T Result (LHS); // Copy LHS to Result
Return Result = rhs; // RHS adds it and returns the result
}
This template is almost the same as the previous program, but there is still an important difference between them. The second template contains a naming object, result. This named object means that the return value optimization cannot be used in Operator (see Terms 20). The first implementation method can always use the return value optimization, so the compiler can be more likely to generate an optimized code.
The facts in the advertisement force me to point out the expression:
RETURN T (LHS) = RHS;
The return value optimization is more complicated than most compilers. The first function of the above implementation also has such a temporary object overhead, just like you spending over a named object Result. However, unnamed objects are more easily cleared in history than named objects, so we are better in terms of temporary objects when we face the naming objects and temporary objects. It makes you spending more expensive than named objects, especially when using the old compiler, it will be less expensive.
The name objects, unnamed objects, and compilation optimization here are interesting, but the main point is that the Operator's assignment form (Operator =) is higher than the single form (Operator ) efficiency. As a library program designer, both provide, as a developer for an application, you should consider the form of the Operator assignment when prioritizing performance.