C++|函數三種傳參、返回方式的優勢、劣勢及適用場合

By default, non-pointer arguments in C++ are passed by value. When an argument is passed by value, the argument’s value is copied into the value of the corresponding function parameter.

默認情況下,C++中的非指針參數是通過值傳遞的。按值傳遞參數時,參數的值將複製到相應函數參數的值中。

While pass by value is suitable in many cases, it has a couple of limitations. First, when passing a large struct or class to a function, pass by value will make a copy of the argument into the function parameter. In many cases, this is a needless performance hit, as the original argument would have sufficed. Second, when passing arguments by value, the only way to return a value back to the caller is via the function’s return value. While this is often suitable, there are cases where it would be more clear and efficient to have the function modify the argument passed in. Pass by reference solves both of these issues.

雖然值傳遞在許多情況下都適用,但它有一些限制。首先,當向函數傳遞大型結構或類時,值傳遞會將參數複製到函數參數中。在許多情況下,這是一個不必要的性能消耗,因為原始參數已經足夠了。其次,當按值傳遞參數時,將值返回給調用者的唯一方法是通過函數的返回值。雖然這通常是合適的,但在某些情況下,讓函數修改傳入的參數會更清楚、更有效。“按引用傳遞”解決了這兩個問題。

There is one more way to pass variables to functions, and that is by address. Passing an argument by address involves passing the address of the argument variable rather than the argument variable itself. Because the argument is an address, the function parameter must be a pointer. The function can then dereference the pointer to access or change the value being pointed to.

還有一種方法可以將變量傳遞給函數,那就是按地址傳遞。按地址傳遞參數涉及傳遞參數變量的地址,而不是參數變量本身。因為參數是地址,所以函數參數必須是指針。然後,該函數可以取消對訪問指針的引用或更改所指向的值。

1 Pros and cons of pass by value

1.1 Advantages of passing by value:

In most cases, pass by value is the best way to accept parameters of fundamental types when the function does not need to change the argument. Pass by value is flexible and safe, and in the case of fundamental types, efficient.

1.1.1 Arguments passed by value can be variables (e.g. x), literals (e.g. 6), expressions (e.g. x+1), structs & classes, and enumerators. In other words, just about anything.

1.1.2 Arguments are never changed by the function being called, which prevents side effects.

1.2 Disadvantages of passing by value:

Copying structs and classes can incur a significant performance penalty, especially if the function is called many times.

1.3 When to use pass by value:

When passing fundamental data type and enumerators, and the function does not need to change the argument.

1.4 When not to use pass by value:

When passing structs or classes (including std::array, std::vector, and std::string).

2 Pros and cons of pass by reference

2.1 Advantages of passing by reference:

2.1.1 References allow a function to change the value of the argument, which is sometimes useful. Otherwise, const references can be used to guarantee the function won’t change the argument.

2.1.2 Because a copy of the value of argument is not made(only address), pass by reference is fast, even when used with large structs or classes.

2.1.3 References can be used to return multiple values from a function (via out parameters).

2.1.4 References must be initialized, so there’s no worry about null values.

2.2 Disadvantages of passing by reference:

2.2.1 Because a non-const reference cannot be initialized with a const l-value or an r-value (e.g. a literal or an expression), arguments to non-const reference parameters must be normal

variables.

2.2.1 It can be hard to tell whether an argument passed by non-const reference is meant to be input, output, or both. Judicious use of const and a naming suffix for out variables can help.

2.2.1 It’s impossible to tell from the function call whether the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.

2.3 When to use pass by reference:

When passing structs or classes (use const if read-only).

When you need the function to modify an argument.

When you need access to the type information of a fixed array.

2.4 When not to use pass by reference:

When passing fundamental types that don’t need to be modified (use pass by value).

Rule: Use pass by (const) reference instead of pass by value for structs and classes and other expensive-to-copy types.

3 Pros and cons of pass by address

3.1 Advantages of passing by address:

3.1.1 Pass by address allows a function to change the value of the argument, which is sometimes useful. Otherwise, const can be used to guarantee the function won’t change the argument. (However, if you want to do this with a non-pointer, you should use pass by reference instead).

3.1.1 Because a copy of the argument is not made, it is fast, even when used with large structs or classes.

3.1.1 We can return multiple values from a function via out parameters.

3.2 Disadvantages of passing by address:

3.2.1 Because literals and expressions do not have addresses, pointer arguments must be normal variables.

3.2.1 All values must be checked to see whether they are null. Trying to dereference a null value will result in a crash. It is easy to forget to do this.

3.2.1 Because dereferencing a pointer is slower than accessing a value directly, accessing arguments passed by address is slower than accessing arguments passed by value.

3.3 When to use pass by address:

3.3.1 When passing built-in arrays (if you’re okay with the fact that they’ll decay into a pointer).

3.3.1 When passing a pointer and nullptr is a valid argument logically.

3.4 When not to use pass by address:

3.4.1 When passing a pointer and nullptr is not a valid argument logically (use pass by reference and dereference the pointer argument).

3.4.1 When passing structs or classes (use pass by reference).

3.4.1 When passing fundamental types (use pass by value).

As you can see, pass by address and pass by reference have almost identical advantages and disadvantages. Because pass by reference is generally safer than pass by address, pass by reference should be preferred in most cases.

Rule: Prefer pass by reference to pass by address whenever applicable.

4 Return by value

Return by value is the simplest and safest return type to use. When a value is returned by value, a copy of that value is returned to the caller. As with pass by value, you can return by value literals (e.g. 5), variables (e.g. x), or expressions (e.g. x+1), which makes return by value very flexible.

Another advantage of return by value is that you can return variables (or expressions) that involve local variables declared within the function without having to worry about scoping issues. Because the variables are evaluated before the function returns, and a copy of the value is returned to the caller, there are no problems when the function’s variable goes out of scope at the end of the function.


Return by value is the most appropriate when returning variables that were declared inside the function, or for returning function arguments that were passed by value. However, like pass by value, return by value is slow for structs and large classes.

4.1 When to use return by value:

When returning variables that were declared inside the function

When returning function arguments that were passed by value

4.2 When not to use return by value:

When returning a built-in array or pointer (use return by address)

When returning a large struct or class (use return by reference)

5 Return by address

Returning by address involves returning the address of a variable to the caller. Similar to pass by address, return by address can only return the address of a variable, not a literal or an expression (which don’t have addresses). Because return by address just copies an address from the function to the caller, return by address is fast.

However, return by address has one additional downside that return by value doesn’t -- if you try to return the address of a variable local to the function, your program will exhibit undefined behavior.

Return by address is often used to return dynamically allocated memory to the caller.

5.1 When to use return by address:

When returning dynamically allocated memory

When returning function arguments that were passed by address

5.2 When not to use return by address:

When returning variables that were declared inside the function or parameters that were passed by value (use return by value)

When returning a large struct or class that was passed by reference (use return by reference)

6 Return by reference

Similar to pass by address, values returned by reference must be variables (you should not return a reference to a literal or an expression that resolves to a temporary value, as those will go out of scope at the end of the function and you’ll end up returning a dangling reference,and the style like the the return value for return a noc_local variable). When a variable is returned by reference, a reference to the variable is passed back to the caller. The caller can then use this reference to continue modifying the variable, which can be useful at times. Return by reference is also fast, which can be useful when returning structs and classes.

However, just like return by address, you should not return local variables .

6.1 When to use return by reference:

6.1.1 When returning a reference parameter

6.1.2 When returning an element from an array that was passed into the function

6.1.3 When returning a large struct or class that will not be destroyed at the end of the function (e.g. one that was passed in)

6.2 When not to use return by reference:

6.2.1 When returning variables that were declared inside the function or parameters that were passed by value (use return by value)

6.2.2 When returning a built-in array or pointer value (use return by address)

reference: https://www.learncpp.com/cpp-tutorial/72-passing-arguments-by-value/

-End-


分享到:


相關文章: