Chapter 6 functions of c++primer

Posted by rkolbe on Mon, 20 Dec 2021 10:10:05 +0100

6.1 function basis

  • The return type of a function cannot be an array or function, but can be a pointer to an array or function.

6.1. 1 local object

  • A block is a local scope that hides local variables with the same name outside the block
  • Objects defined outside all functions are created at the start of the program and destroyed at the end of the program.
  • Local objects are created when the statement is defined and destroyed at the end of the block.
  • Automatic object initialization
    • The variable definition contains an initial value, which is used for initialization
    • Otherwise, default initialization may result in undefined values.
  • A local static object is initialized when the program first passes through the object definition statement and is not destroyed until the program terminates.

6.1. 2 function declaration

  • Function in header file
    It can ensure that all declarations of the agreed function are consistent. If it needs to be modified, just modify one declaration; It is legal to put it in the source file, but it is error prone.
  • The header file containing the function declaration should be included in the source file.

6.1. 3 separate compilation

  • Separate compilation can be used when modifying a single file.
    Such as G + + fact cpp factMain.cpp generates an a.out. Modify factmain After the content in CPP, you need to use this command again to recompile all links.
    In fact, it can be divided into two parts: Compilation and linking
g++ -c fact.cpp #Compile and generate fact o
#If you modify factmain CPP performs the following three steps
g++ -c factMain.cpp #Compile and generate factmain o
g++ fact.o factMain.o #Link to generate a.out executable
g++ fact.o factMain.o  -o main #Link to generate the main executable

6.2 function transfer

  • When the formal parameter is a reference type, the argument is passed by reference (or the function is passed by reference)
  • When the argument value needs to be copied to the formal parameter, the argument is called by value transfer (or function value transfer). The formal parameter and the argument are independent of each other, and the actual parameter is copied and constructed in the function block (copy construction is in Chapter 13).

6.2. 1. Value transfer parameters

In c + +, it is recommended to use reference type instead of pointer

6.2. 2. Pass reference parameters

  • Use references to avoid copying values
    Because copying large classes unnecessarily consumes resources, and some classes do not support copy operations, such as iostream
  • If the function does not need to change the value of the reference parameter, it is best to declare it as a constant reference
  • Use reference arguments to return additional information

6.2.3 const formal and argument

  • When an argument initializes a formal parameter, the top const is ignored, but the bottom const is retained.
    That is, if the passed in pointer (or reference) is const at the top level, it cannot re point to (or represent) other variables. There is no such restriction in the function body, and it can re point to (or represent) other variables.
  • You can initialize an underlying const object with a non constant, but not the other way around
  • When declaring functions, try to use constant references
    It is an error to define a parameter that will not change as a normal reference, which will mislead the function caller. This function will change the value of the argument and limit the type of argument accepted by the function
int find_char(string& s);
string s("infinite~");
const string cs("Luo Xiaohei");
find_char(s);//Can call
find_char(cs);//Cannot initialize a non constant with const, and an error occurs when compiling

find_char2(const string& s);
find_char2(s);
find_char2(cs);//Can be called normally

6.2. 4 array parameters

  • The array is passed to the function as a pointer.
    Even within a function, the programmer should ensure that the array cannot cross the boundary. There are three ways to tell the function the size of the array.
    • The array itself contains a marker. For example, the character array can be marked with \ 0.
    • Take the pointers of the first and last elements of the array as parameters
    • Pass a formal parameter representing the size of the array
//This form is allowed, but it is also dangerous. The compiler will convert ia to pointer type
//No error will be reported when passing in an array whose size is not 10
void print(const int ia[10]){
    for (size_t i = 0;i<10;i++){
        cout << ia[i] << endl;
    }
}
int main(){
    int a[5]={1,2,3,4,5};
    print(a);//The situation is unknown
}
  • Allows function parameters to define references to arrays, and the array dimension is also part of the parameter type
//The function can only act on int arrays of size 10
//&There must be parentheses around arr. Int & arr [10] is a referenced array, not an array reference
void fun(int (&arr)[10]) 
  • If you need to use multidimensional array as a function parameter, the second dimension (and all subsequent dimensions) of the function is a part of the array and cannot be omitted.
//matrix is a pointer to an array containing 10 integers
void fun(int (*matrix)[10],int rowsize);
//Equivalent definition
void fun(int matrix[][10],int rowsize);

6.2. 5 mainprocessing command line options

Sometimes you need to pass arguments to main, such as telling the function what to do.
Suppose the program is in the executable prog, and you want to enter the following options into the program

prog -d -o ofile data0

main can be declared in the following form

int main(int argc,char** argv);

argv is an array whose elements are c-style string pointers
argc is the number of elements in argv.
If the input command is prog -d -o ofile data0, argc is 5, argv[0] to argv[4] are prog -d -o ofile data0 in turn. argv[5] is 0.

argv[0] is the program name, argv[1] is the available argument

6.2. 6 functions with variable parameters

  • There are two main methods, one of which is not commonly used to deal with functions with different numbers of arguments
    • Main method 1: the argument types are the same. Use the standard library type, initializer_list
    • Main method 2: variable parameter template with different argument types (described in section 16.4)
    • Very useful: ellipsis formal parameter, which is only used for interface program interacting with c function
  • initializer_list
    • initializer_ The elements in the list object are always constants
  • Ellipsis parameter
    • The ellipsis parameter is used to access some special c code that uses the c standard library function called varargs.
    • Ellipsis parameters are only used for types common to c and c + +, and most class types cannot be copied correctly when passed to ellipsis parameters
    • There are two forms:
void foo(para_list,...);//If some parameter types are specified, normal type checking will be performed on the specified type, and the comma character is optional
void foo(...);//The argument corresponding to the ellipsis parameter does not need type checking

6.3 return type and return statement

6.3. 1 function with no return value

You can use return; Or return void;

6.3. 2 function with return value

  • There should also be a return statement after the loop statement containing the return statement. If there is no return statement, the program is wrong. But many compilers cannot find this error.
bool cmp_test(const string& str1,const string& str2){
    auto size = str1.size()<str2.size()?str1.size():str2.size();
    for (decltype(size) i = 0;i<size;++i){
        if(str1[i]!=str2[i]){
            return   ;//Error, but the compiler may not find it
        }
    }
}
  • Do not return references and pointers to local objects or undefined values.
    When returning, it is generally a copy of the return value, which is safe; But it is dangerous to return only a copy of a pointer or reference to a local object.
  • The priority of the calling operator and the point operator are the same as that of the arrow operator, and comply with the left Association law.
    Therefore, you can directly call the object that returns the pointer or class
shorterString(s1,s2).size()
  • Return a referenced function to get the left value, and other types to get the right value
  • You can use the initialization list to return values
vector<string> fun(){
	//Initializes the vector using the returned initialization list
	return {"string1","string2","string3"};
}
  • The return value of main is regarded as a status indicator. Returning 0 indicates success and others indicate failure.
    • The specific meaning of non-zero value depends on the machine
    • The main function cannot call itself recursively
    • Preprocessing variables are defined in the cstdlib header file to indicate success or failure
int main(){	
	if(some_fail) return EXIT_FAILURE;
	else return EXIT_SUCCESS;
}

6.3. 3 return function pointer

  • Define a function that returns an array pointer. The dimension of the array must follow the function name
//Function definition
Type (*function(parameter_list))[dimension]
//The func function returns an array pointer that points to an array of 10 int types
int (*fun(int i ))[10];
//fun(int i ) 			 Indicates that the function requires an int argument
//(*fun(int i )) 		 Indicates that the function can be dereferenced
//(* fun (int i)) [10] indicates that the reference operation obtains an array of size 10
//Int (* fun (int i)) [10] indicates that the elements in the array are of type int
  • Use trailing return type
auto fun(int i)->int(*)[10]
  • Use decltype
int arr[]={0,1,2,3,4,5,6,7,8,9}
decltype(arr) *fun(int  i);

6.4 function overloading

  • Overloaded function: the function name is the same, but the formal parameter list is different. (different return values are not recognized)
  • The main function cannot be overloaded
  • The top-level const parameter cannot be distinguished from another parameter without the top-level const, but the bottom const can be recognized (when the parameter is a pointer or reference, it can distinguish between pointing to constant objects and non constant objects to realize overloading)
Record lookup(Phone);
Record lookup(const Phone);//Cannot distinguish from Record lookup(Phone)

Record lookup(Phone*);
Record lookup(const Phone*);//Correct, different from Record lookup(Phone *)
  • It's best to overload only those very similar operations.
  • const_ Use of cast in function
const string& shorterString(const string& s1,const string& s2){
	return s1.size()<+s2.size()?s1:s2;
}

string& shorterString(string& s1,string& s2){
auto &r = shorterString(const_cast<const string&>(s1),const_cast<const string&>(s2));
return const_cast<string &>(r);
}

  • Three results of function calls
    • The compiler finds the best match for the arguments and generates the code for the function.
    • If the best match of an appropriate argument cannot be found, the compiler method throws a no match error
    • More than one function can be matched, but each is not the best choice. The compiler issues a ambiguous call error

6.4. 1 overload and scope

  • It is unwise to put the function declaration in the local scope. The following is only an explanation of c + + features and is not recommended
    In different scopes, functions are not overloaded but hidden
void print(string str);
int main(){
	//Bad declaration in new scope
	void print(int ival);
	//Error, because the function with string parameter has been hidden
	print("ni hao");
}

6.5 special purpose language features

6.5. 1 default argument

  • Once a form is given a default value, all formal parameters behind it must have a default value
  • In general, you should specify the default argument in the function declaration and put the declaration in the appropriate header file
  • Local variables cannot be used as default arguments. As long as the type of the expression can be converted to the type required by the formal parameter, the expression can be used as the default argument.
sz wd=80;
char def =' ';
sz ht();
string screen(sz = ht(),sz = wd,char =def);
string window = screen();//Call screen(ht(),80, '')
void f2(){
	def ='*';
	sz wd =100;//The rest of wd
	window = screen();//Call screen(ht(),80, '*')
	}

6.5. 2 inline function and constexpr function

  • Inline function
    • Inline functions are expanded at the call point to avoid the cost of function calls
    • Add inline before the return value of the function
    • The inline description simply makes a request to the compiler, which can be ignored by the compiler
    • Inline mechanism is generally used to optimize functions with small scale, direct process and frequent calls.
    • Many compilers do not support introverted recursive functions
  • constexpr function
    • constexpr functions are functions that can be used in constant expressions
    • Requirements for constexpr function:
      • The return value type and the types of all formal parameters are literal types
      • There is only one return statement in the function body.
      • If there are other statements, they cannot perform any operations, such as empty statements, type aliases, using declarations.
    • The constexpr function is implicitly specified as an inline function
  • Inline functions and constexpr functions are placed in the header file

6.5. 3 debugging help

You can debug code using the preprocessing capabilities of assert and NDEBUG

  • assert preprocessing macro
    • Assert (expr). If expr is true, assert does nothing; otherwise, assert outputs information and terminates program execution.
    • The assert macro is defined in the cassert header file
    • Preprocessing names are managed by the preprocessor rather than the compiler, so you can avoid using declarations
    • Programs with cassert header files cannot use variables, functions, or other entities named assert.
      Even if you don't include the cassert header file directly, you may include the header file indirectly, so it's best not to use variables, functions or other entities named assert
  • NDEBUG preprocessing variables
    • If NDEBUG is defined, assert does nothing
    • Method of using NDEBUG
      • Using #define NDEBUG in a program
      • Add commands during compilation, such as CC - D ndebug main cpp
    • Use NDEBUG to write conditional debugging
void print(){
	#ifndef NDEBUG
	//__ func__ Is a compiler defined static local constant used to store the function name
	cerr<<__func__<<"debugging"<<endl;
	#endif
	...
}
  • Compiler in addition to definition__ func__ In addition, the following variables are defined
    • __ FILE__ The string literal that holds the file name
    • __ LINE__ The integer literal that holds the current line number
    • __ TIME__ String literal that holds the compilation time of the file
    • __ DATE__ String literal that holds the date and time of the file

6.6 function matching

  • Step 1: determine candidate functions. The candidate function has the same name as the called function and is visible at the call point.
  • Step 2: determine the feasible function. The formal parameters of the feasible function are equal to the number of arguments provided by this call. The type of each argument is the same as the corresponding formal parameter type or can be converted into formal parameter type
  • Step 3: determine the best match

When calling overloaded functions, you should try to avoid cast. If mandatory type conversion is required, it indicates that the design of formal parameter set is unreasonable.

6.6. 1 argument type conversion

  • The conversion from argument to type is divided into five levels
    • Exact match
    • Matching through const transformation
    • Matching through type promotion
    • Matching by arithmetic type conversion or pointer conversion
    • Matching through class type conversion

6.7 function pointer

  • The function pointer points to a function, not an object. Its type is determined by the return type and formal parameter type, independent of the function name.
  • Function pointer declaration: replace the function name with a pointer
//Function declaration
bool lenghthCmp(const string& s1,const string& s2);
//The function pointer declares that the brackets of (* pf) cannot be less, otherwise it returns a pointer to bool
bool (*pf)(const string& s1,const string& s2);
//The following assignment is equivalent and optional when taking the address character
//However, the function prototype and return value should be exactly consistent with the pf declaration
pf = lenghthCmp;
pf = &lenghthCmp;

//The following are equivalent calls
bool b1=pf("hello","goodbye");
bool b2=(*pf)("hello","goodbye");
bool b1=lenghthCmp("hello","goodbye");
  • The function pointer can be used as the parameter of the function, and the function name can be directly used as the argument. Functions as arguments are implicitly converted to function pointers.
  • decltype and type alias can be used to simplify the declaration of function pointers
//Same declaration
void useBigger(const string &s1,const string &s2,bool pf(const string &,const string &));
void useBigger(const string &s1,const string &s2,bool (*pf)(const string &,const string &));
//call
useBigger(s1,s2,lenghthCmp)

//fun1 and fun2 are function types
typedef bool fun1(const string &,const string &);
typedef decltype(lenghthCmp) fun2;
//Funp1 and funp1 are pointer types
typedef bool (* funp1)(const string &,const string &);
typedef decltype(lenghthCmp) *funp1;
  • Returns a pointer to a function
    Function pointers are different as return types and as arguments.
    Functions are automatically converted to pointers as arguments, but not as return values
using F = bool(const string &,const string &);//Function type
using Fp = bool(*)(const string &,const string &)//Pointer type, (*) parentheses are also necessary
//You can also use trailing return types
auto Fp2(const string &,const string &)->bool(*)(const string &,const string &);

Topics: C++