C ++ software development specifications-continued

Source: Internet
Author: User

4. Function Design

Functions are the basic functional units of C ++/C Programs. Their importance is self-evident. The minor disadvantage of function design can easily lead to incorrect use of the function. Therefore, it is not enough to make the function correctly. This chapter focuses on the interface design and internal implementation rules of functions.

Two elements of a function interface are parameters and return values. In C, function parameters and return values are transmitted in two ways: pass by value and pass by pointer ). Pass by reference is added to the C ++ language ). Because the nature of reference transfer is like pointer transfer, but the usage is like value transfer, beginners are often confused and prone to confusion. Please read section 6.6 "Comparison of reference and pointer" first ".

4.1 parameter rules

☆[ Rule 4.1-1] The parameters should 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] The parameter name 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, 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 pass the object, in this way, the construction and analysis processes of temporary objects can be omitted to improve efficiency;

☆[ 4.1-1 Recommended] avoid having too many parameters in the function. The number of parameters should be limited to five. If there are too many parameters, the parameter type or order may be incorrect during use;

[4.1-2] Do not use parameters with uncertain types and 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.2 return 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 mark to return the result. The normal value is obtained using the output parameter, and the error mark is returned using the return statement;

☆[ Recommended 4.2-1] Sometimes the function does not need to return values, but to increase flexibility, such as supporting chained expressions, the return value can be appended;

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, replacing "value transfer" with "reference transfer" in some cases 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.3 internal implementation rules of functions

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.

4.4 Other suggestions

☆[ Recommended 4.4-1] functions should be single, and do not Design multi-purpose functions;

☆[ Recommended 4.4-2] the size of the function body should be small and should be controlled within 150 lines of code as much as possible;

☆[ 4.4-3] avoid having the "Memory" function in the function whenever possible. The same input should generate the same output function with the "Memory" function, and its behavior may be unpredictable, because its behavior may depend on a certain "memory state ". Such functions are hard to understand and are not conducive to testing and maintenance. In C/C ++, the static local variable of the function is the memory of the function. We recommend that you use less static local variables unless necessary.

☆[ Recommended 4.4-4] not only check the validity of input parameters, but also check the validity of variables entering the function body through other channels, such as global variables and file handles;

☆[ Recommended 4.4-5] The returned values for error handling must be clear, so that the user cannot easily ignore or misunderstand the error.

4.5 Use assertions

Programs are generally divided into Debug and Release versions. The Debug version is used for internal debugging, And the Release version is released to users.

Assert is a macro that only works in the Debug version. It is used to check the situation where "no" occurs. Example 4.5 is a memory replication function. During the running process, if the assert parameter is false, the program will stop (generally, a dialog prompt will appear, indicating where the assert is triggered ).

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.