Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to make passing by reference, and passing by value explicit in the function call?

Tags:

If you were to look at this code,

int x = 0; function(x); std::cout << x << '\n'; 

you would not be able to verify through any means of syntax, that parameter x is being passed by reference or that it's being passed by value. The only way you would know for sure, is if you looked at either the function declaration or function definition.

Here is a simple example of how I believe this could be a problem:

std::string Lowercase(std::string str); //<- this is hidden away in code; probably in a different file.  int main(){     std::string str = "HELLO";     Lowercase(str);     std::cout << str << '\n'; //<- Bug! we expected to output "hello".  The problem is not very easy to spot, especially when a function name sounds as though it will change the passed in value. } 

In order to avoid having to jump between the function call and the function declaration (or in some cases, the documentation) in order to understand the function behavior, is there a way to explicitly document in the syntax of a function call that the parameter is expected to change (i.e. a reference parameter) or that a copy is being sent (i.e. pass by value)?

I realize that there is also the option of passing by const& which has the similar notion to passing by value, in that the variable passed in, will not have its value changed after the function call.


I'm sure there are all kinds of situations in the language that might add to the complexity of understanding how a parameter is being passed- but I'm curious, is there a way to combat this problem in the way I want to?

I've noticed that some people write two similar functions. One of them takes a value parameter, the other one takes a pointer. That allows calling a function like this:

Lowercase(str); //we assume the value will not change Lowercase(&str); //we assume the value will change 

But this solution has many other issues, and I would not like to lose the benefit of references. Plus, we are still making assumptions on the behavior.

like image 268
Trevor Hickey Avatar asked Nov 05 '13 23:11

Trevor Hickey


People also ask

How can you pass value by reference in function?

To pass a value by reference, argument pointers are passed to the functions just like any other value. So accordingly you need to declare the function parameters as pointer types as in the following function swap(), which exchanges the values of the two integer variables pointed to, by their arguments.

What is passing by value and passing by reference?

"Passing by value" means that you pass the actual value of the variable into the function. So, in your example, it would pass the value 9. "Passing by reference" means that you pass the variable itself into the function (not just the value). So, in your example, it would pass an integer object with the value of 9.

Is pass by value and call by value same?

They are synonymous. The term call-by-value means exactly the same as pass-by-value. However, I prefer the pass-by-value form, as it's the parameter that is passed that it refers to. A call can have parameters that are passed by value as well as parameters passed by reference.

Can you pass a variable by reference?

Pass by reference is something that C++ developers use to allow a function to modify a variable without having to create a copy of it. To pass a variable by reference, we have to declare function parameters as references and not normal variables.


2 Answers

Some people insist that the correct way to pass mutable object is to use a pointer. That is, you would pass

Lowercase(&str); 

... and Lowercase() would, obviously, be implemented to take a pointer. That approach may suit your needs.

I want to mention, however, that this is not what I would do! Instead, the approach I favor is to use appropriate names instead. For example,

inplace_lowercase(str); 

pretty much says what it is going to do. Clearly, inplace_lowercase() would actually be an algorithm and with a bit of magic could be reasonably be called as

inplace_lowercase(str.begin() + 1, str.end()); 

as well.

Here are a few reasons why I don't like passing arguments by pointer and/or why I don't believe in an explicit indication of how the argument is passed:

  • Pointers can be null. A mandated reference parameters should, in my opinion, be a reference.
  • Passing by pointer still doesn't indicate whether the argument may be modified are not as the argument may be a T const*.
  • Having meaningful names makes it actually easier to understand what's going on in the first place.
  • Calling something without consulting its documentation and/or knowing what the called function will do doesn't work anyway and indicating how things are passed is trying to cure symptoms of a deeper problem.
like image 57
Dietmar Kühl Avatar answered Oct 09 '22 02:10

Dietmar Kühl


I'm not sure I understand your requirements completely, but maybe this is something you can use:

template<typename T> void foo( T ) { static_assert( sizeof(T)==0, "foo() requires a std::ref" ); }  void foo( std::reference_wrapper<int> t ) {     // modify i here via t.get() or other means of std::reference_wrapper }  int main() {     int i = 42;     // foo( i ); // does not compile, static_assert fires     foo( std::ref( i ) ); // explicit std::ref visible on the caller's side } 
like image 27
Daniel Frey Avatar answered Oct 09 '22 02:10

Daniel Frey