4.1Parameter rules
☆[Rule 4.1-1]The parameters must be completely written. Do not worry about writing only the parameter type and omitting the parameter name. If the function does not have a parameter, fill it with void. For example:
Void setvalue (INT nwidth, int nheight); // good style
Void setvalue (INT, INT); // bad style
Float getvalue (void); // good style
Float getvalue (); // bad style
☆[Rule 4.1-2]Parameter names should be appropriate and the order should be reasonable;
For example, compile the string copy function stringcopy, which has two parameters. If the parameter names are str1 and str2, for example:
Void stringcopy (char * str1, char * str2 );
It is difficult to figure out whether to copy str1 to str2 or just reverse it. You can make the parameter name more meaningful, such as strsource and strdestination. In this way, we can see that strsource should be copied to strdestination. There is another question: Which of the two parameters should be the first one after? The order of parameters must follow the programmer's habits. Generally, the target parameter should be placed first, and the source parameter should be placed later. If you declare a function:
Void stringcopy (char * strsource, char * strdestination );
When using it, others may write the following form without thinking about it:
Char STR [20];
Stringcopy (STR, "Hello World"); // The Order of parameters is reversed.
☆[Rule 4.1-3]If the parameter is a pointer and only used for input, you should add const before the type to prevent the pointer from being accidentally modified in the function body. For example:
Void stringcopy (char * strdestination, const char * strsource );
☆[Rule 4.1-4]If the input parameter is passed as a value, you should use the "const &" method to transfer the object. This saves the construction and analysis processes of the temporary object and improves the efficiency;
☆[4.1-1 Recommended]Avoid too many parameters in a function, and set the number of parameters to less than 5. If there are too many parameters, the parameter type or order may be incorrect during use;
☆[Recommended 4.1-2]Do not use parameters with uncertain types or numbers;
The C standard library function printf is a typical example of using uncertain parameters. Its prototype is:
Int printf (const chat * Format [, argument]…);
This type of function loses strict type security checks during compilation.
4.2Return Value rules
☆[Rule 4.2-1]Do not omit the type of the returned value;
In C language, all functions without type descriptions are automatically processed by integer type, which is easy to be misunderstood as void type;
The C ++ language has strict type security checks and does not allow the above situations. Since C ++ programs can call C functions, to avoid confusion, it is required that any c ++/C function must have a type. If the function does not return a value, the void type should be declared.
☆[Rule 4.2-2]The function name and return value type cannot conflict in semantics;
A typical violation of this rule is the c Standard library function getchar.
For example:
Char C;
C = getchar ();
If (C = EOF)
...
According to the getchar name, it is natural to declare the variable C as the char type. Unfortunately, getchar is not a char type but an int type. Its prototype is as follows:
Int getchar (void );
Because C is of the char type and the value range is [-128,127], if the macro EOF value is out of the char value range, the IF statement will always fail, this kind of "dangerous" is generally expected! The fault in this example is not caused by the user. The getchar function misleads the user.
☆[Rule 4.2-3]Do not mix the normal value with the error flag to return the result. The normal value is obtained using the output parameter, and the error mark is returned using the return statement;
☆[4.2-1 Recommended]Sometimes a function does not need to return values, but to increase flexibility, such as supporting chained expressions, you can add return values;
For example, the prototype of the string copy function strcpy:
Char * strcpy (char * strdest, const char * strsrc );
The strcpy function copies strsrc to the output parameter strdest, And the return value of the function is strdest. In this case, the following flexibility can be achieved:
Char STR [20];
Int nlength = strlen (strcpy (STR, "Hello World "));
☆[Recommended 4.2-2]If the return value of a function is an object, in some cases, replacing "value transfer" with "reference transfer" can improve the efficiency. In some cases, you can only use "value transfer" instead of "reference transfer". Otherwise, an error occurs;
It is recommended that 4.2-2. If the return value of a function is an object, replacing "value transfer" with "reference transfer" may improve the efficiency, in some cases, you can only use "value transfer" instead of "reference transfer". Otherwise, an error occurs, for example:
Class string
{...
// Value assignment function
String & operate = (const string & other );
// Add function. If there is no friend modifier, only one parameter on the right is allowed.
Friend string operate + (const string & S1, const string & S2 );
PRIVATE:
Char * m_data;
};
The implementation of the string value assignment function operate = is as follows:
String & string: operate = (const string & other)
{
If (this = & other)
Return * this;
Delete m_data;
M_data = new char [strlen (other. Data) + 1];
Strcpy (m_data, other. data );
Return * This; // The returned result is a reference of * This, without the need to copy the process.
}
For the value assignment function, the string object should be returned using the "reference transfer" method. If the "value transfer" method is used, although the function is still correct, but because the return statement needs to copy * this to the external storage unit that saves the returned value, unnecessary overhead is added, this reduces the efficiency of the value assignment function. For example:
String A, B, C;
...
A = B; // If "value transfer" is used, a * This copy will be generated.
A = B = C; // If "value transfer" is used, two * This copies will be generated.
The implementation of the string addition function operate + is as follows:
String operate + (const string & S1, const string & S2)
{
String temp;
Delete temp. Data; // temp. Data is a string containing only '/0'.
Temp. Data = new char [strlen (s1.data) + strlen (s2.data) + 1];
Strcpy (temp. Data, s1.data );
Strcat (temp. Data, s2.data );
Return temp;
}
For Addition functions, the string object should be returned using the "value transfer" method. If "reference transfer" is used, the return value of the function is a "Reference" pointing to the local object temp ". Because temp is automatically destroyed at the end of the function, the returned "Reference" is invalid. For example:
C = A + B;
At this time, A + B does not return the expected value, and C does not get anything, causing hidden risks.
4.3Internal function implementation rules
Different functions have different internal implementations, and it seems impossible to reach an agreement on internal implementations. However, based on experience, we can strictly control the "ENTRANCE" and "exit" of the function body to improve the function quality.
☆[Rule 4.3-1]Check the parameter validity at the "ENTRANCE" of the function body;
Many program errors are caused by Invalid parameters. We should fully understand and correctly use assert to prevent such errors. For details, see section 4.5 "Use assertions"
☆[Rule 4.3-2]Check the correctness and efficiency of the Return Statement at the "exit" of the function body;
Note:
(1) The return statement cannot return "Pointer" or "Reference" pointing to "stack memory" because the function body is automatically destroyed when it ends. For example:
Char * func (void)
{
Char STR [] = "Hello World"; // the memory of STR is on the stack.
...
Return STR; // Error
}
(2) Determine whether the returned result is "value", "Pointer", or "Reference ";
(3) If the return value of a function is an object, consider the efficiency of the Return Statement, for example:
Return string (S1 + S2 );
This is the syntax of a temporary object, indicating "Creating a temporary object and returning it". Do not think it is equivalent to "Creating a local object temp first and returning its results", for example
String temp (S1 + S2 );
Return temp;
Otherwise, the above Code will have three things.
First, the temp object is created and initialized;
Then, the copy constructor copies temp to the external storage unit that saves the returned values;
Finally, temp is destroyed at the end of the function (calling the destructor ).
However, the process of "Creating a temporary object and returning it" is different. The Compiler directly creates and initializes the temporary object in an external storage unit, saving the copy and destructor fees, improved efficiency.
Similarly, we do not want
Return int (x + y); // create a temporary variable and return it
Write
Int temp = x + y;
Return temp;
Because the internal data types such as int, float, and double do not have constructor and destructor, although the "Syntax of temporary variables" does not increase much efficiency, the program is more concise and easy to read.