change a passed by value

Why is it rare to change the value of an argument that is passed by value?
Last edited on
It's not rare. Don't get caught up in ideologies. Programming is about you expressing your ideas through code. If you're making a program that passes by value thousands of times, so be it! If you're making one that passes by references thousands of times, so be it!
It's all about solving the problem, no matter what.
many times the object is passed this way to avoid copying large classes / containers/etc locally. Those should be tagged constant but often, they are not.

@HandsomeJohn, Stroustrup says in the eighth chapter of his book(Programming using C++) that
"This is not common for a non-reference parameter of a function to be const"
, then I searched for the reason of it and found this on Stackoverflow:
"It cannot hurt to declare it const if you know that your function needs not modify its value during execution.
Note that functions that change their arguments, when arguments are passed by value, should be rare.
Declaring your variable const can prevent you from writing if (aIn = someValue)."
Last edited on
sorry I read that backwards; I thought you were asking why you pass by reference but don't actually change it.

Pass by value and change it... seems like that would fall into style more than anything else. I can't comment on the frequency that it might have happened in the history of the world, but that seems like a bold thing to guess about. I personally do not do it much, but most of my code is math processing and doing that just makes the code confusing. Its just weird to be reading code thinking it is talking about the input parameter but it is instead some other value. If you missed the assignment, or the assignment is masked in a function call (talk about tricksy... passed into a pass by reference that modifys it but it was originally a pass by value!) ... all this stuff just makes confusion and serves no purpose.
In short, the purpose of a function parameter is to take input from its caller. When a value parameter is overwritten you may be falling into variable recycling. For example:
1
2
3
double mass_in_kilograms = truck.mass;
//...
mass_in_kilograms /= kilograms_per_pound;
At the end of the example, mass_in_kilograms no longer contains the thing it says it contains. Now you have to be more careful because the same variable has a different meaning at different points in the computation.
The case is the same for function parameters.

Note, however, that sometimes overwriting a function parameter can be useful:
1
2
3
4
5
void greatest_common_divisor(int a, int b){
    if (a > b)
        std::swap(a, b);
    //...
}
In this case, overwriting the parameters makes the code simpler, because it doesn't need to explicitly handle the case where the arguments are given in reverse order.
That quote from SO is an opinion, and a wrong one at that. The purpose of a function's interface is to make promises about what that function may or may not do to your data. It is not, and no one should want to know or care, any restriction on how the function works underneath.

It follows that declaring a const value formal is both TMI and non-sequitur.

Further, there is absolutely nothing wrong with using a value argument as if it were any other local variable; in point of fact, doing so is common in all kinds of code, including libc's sources, the Standard Library's sources, etc
I actually posted this question in the beginner's section to get easier answers but the answers here are really quite above my understanding. Could someone else please give a more straight and clear answer?
P.S. No offense to any of the buddies. Maybe the fact that English is not my mother tongue adds to my problem here. "Fall into style", "non-sequitur", etc. are just weird to me. :)
Last edited on
Sorry, here:

Q: "Why is it rare to change the value of an argument that is passed by value?"
A: It is not rare, it is common.

Stroustrup is using a double negative. He is saying that code like the following is rare:
    void foo( const int x )

The commentary from Stack Overflow is, at least in the context here, wrong. You can, of course, write code like the above, but why bother?

"fall into style" is an odd construct that is easy to misread. To "fall into" something means that it can be catagorized as that something, in this case, "style", which is itself an abbreviation for "programming style". What jonnin is saying, then, is that using 'const' on value arguments is something that is a matter of programming style. If you work for a company that requires it, do it. It makes no difference otherwise.

"non-sequitur" means "it doesn't follow" which is another way of saying that something makes no sense.

Here is an example of a function that uses the value argument like any normal variable:

1
2
3
4
5
6
7
const char* strchr( const char* s, char c )
{
  while (*s)
    if (*s == c) return s;
    else s++;
  return NULL;
}

Here's another:
1
2
3
4
5
6
7
template <typename Iterator, typename T>
Iterator fill_n( Iterator iter, std::size_t n, const T& value )
{
  while (n--)
    *iter++ = value;
  return iter;
}

Hope this helps.
If data is passed by reference const will tell the caller that the passed data will not be modified.

If data is passed by value const is irrelevant for the caller because the passed data will be copied and thus not changed. Making such a paramter const none the less will only be relevant for the internal processing of the function.
Exactly. Here are some examples. With the following code:

1
2
  int a = 7;
  does_something( a );

We can now imagine three different declarations of does_something():

void does_something( int& x );
This function does something, presumably modifying a.

void does_something( const int& x );
This function also does something, but promises not to modify a in any way.

void does_something( int x );
Would it really matter if x were const or not? Nothing happens to a either way.

:O)
Hooray! Clear now! Thank you all!
Note that functions that change their arguments, when arguments are passed by value, should be rare.

It’s hard to guess what that user meant when s/he wrote that sentence, but perhaps it can make some sense.

The topic “passing parameters to functions” (together with returning from functions) involves pass by value, which could imply copy elision, copy and move constructors, references, pointers, dynamically allocated objects and... I can’t imagine how far we could go.

IMHO, the problem is, if we stick to primitive types (int, double, char...) everything goes fine and we could simply ignore that sentence. Those types are so ‘light’ and easy to manage for the compiler that we can chose what we like better:
Do I want my value not to be changed by the function? I just pass it by value: I’m guaranteed the original value will remain unaffected.

Do I want the compiler to help me or my code to be easier to read? I can add a ‘const’.
As that poster said, in a situation like the following
1
2
3
4
5
int myfunc(const int i) {
    int a = 13;
    if(a = i) { /* ... */ }
    return a;
}

the compiler will refuse to compile instead of just warning me - so, if I’m one of those who disregard warnings, I’ll be saved by the fact i is const.

Alternatively, do I want my value to be different after the function execution?
I can pass it by (non const) reference or I can still pass it by value and then remember to store the returning value somewhere in the caller.
So far, so simple.

But the more we write code, the less we find ourselves dealing only with primitive types. Actually, we usually need to deal with potentially expensive to copy types - and that means we very often pass our parameters by reference.
In that case, we usually say: if I want my object to be modified, I pass it by reference; if I don’t want it to be modified, I pass it by const reference.
Again, it looks pretty simple.
But what if I want my object to be modified, but later I want those modifications to disappear at the end of the function?

Well, it could sound a bit strange, but it can happen, doesn’t it?
If so, the question is: how many times does it happens? Is it a common experience for you?
We can obtain that easily passing an object by value and than not returning its new value, but the question is not how we can do that, but how many times it happens we want that.

I’ve tried to remember the code I’ve written recently, and it only came to my mind once I wrote a function which interpreted a code inside a string. Throughout the function I deleted the already interpreted character, modifying the passed string. The simplest choice was of course passing the string by value, so that it could be freely modified.

Now, either my memory betrays me, or I’m a terrible programmer, or it’s not common to modify parameters passed by value. It doesn’t mean it’s wrong, just it’s uncommon. Usually, if you modify a parameter, it’s because you need that new value later. But, if it’s passed by value, or you correctly return and store it or that modifications will die together with the function.
My interpretation is that user wanted to say: if you pass your parameter (which is not a primitive type) by value and you modify it, check your code again because it’s not so common to do that. But of course it could be the perfect solution for that particular case.

Or maybe I’m just writing a lot of <censored>. So, please, feel free to correct me as harshly as you wish, I’m eager to learn.
Now, either my memory betrays me, or I’m a terrible programmer, or it’s not common to modify parameters passed by value.

...according to you.

I've already provided plenty of perusal material (C and C++ core libraries) for functions that modify their value arguments, not to mention two examples right here in this thread.

It is not uncommon to modify value arguments.


But what if I want my object to be modified, but later I want those modifications to disappear at the end of the function?

You have basically described the behavior of all value arguments, regardless of the complexity of the argument type.

I'm still not sure why you are making an issue about type, though; how do you propose un-modifying a value before returning?

Modifying a value without modifying the original value necessitates a copy, regardless of type complexity. Believe in your compiler to make that as efficient and painless as possible — it is its job.
That was a pretty long post to say basically nothing.
EDIT: I'm talking about Enoizat's.
Last edited on
Ah, but you've got to read between the lines. Ask yourself, "Self, why would Enoizat post that?" Two options right off the top of my head:

  1. He’s arrogant about how smart he is and wants to present a supposedly equal-but-valid POV.

  2. He is struggling with understanding this himself and wants to get his prior understanding validated/corrected.

The content of his post leads me to believe #2, so that’s why it is worth taking the time to reiterate a couple of points, and to help clear up a few of the misconceptions that led to the misunderstanding.

We all need that kind of response every now and then. That way we all get smarter. ;^]
> Do I want the compiler to help me or my code to be easier to read? I can add a ‘const’.

Yes; if adding a const qualifier to the parameter passed by value would help you write more robust code (prevent the inadvertent modification of an object), by all means do it. Using const proactively is a good idea.

However, to the caller of the function, semantically it makes no difference whether the type of an argument passed by value is const-qualified or not; what a function does with the copy of the object it receives is an implementation detail, internal to the function, and is of no interest to the caller.

So, do not add a const qualifier in the declaration of the function (make it easier to read for the users of the function); but the const qualifier may be added to in the implementation of the function.
(The const qualification on a parameter passed by value is ignored for determining the type of the function.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>

void foo( std::string str ) ; // declaration (typically in a header)

int main()
{
    std::string str = "abcd" ;
    foo(str) ;
}

void foo( const std::string str ) // implementation: const qualifier added
{
    std::cout << str << '\n' ;

    // whatever, but we do not intend to modify the string

    // invariant: the value of str is what it was on entry to the function

    // ...
}
closed account (48T7M4Gy)
@OP

Why is it rare to change the value of an argument that is passed by value?

I don't know about rare, but we have to be careful. The dreaded array is an example of possible unintended consequences where you might think it's safe to pass by value when in fact the underlying scene is such that the array is being passed by reference. Often this is good, but sometimes const offers the required protection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

void function(int ary[] , int size, int change)
{
    ary[0] = change; // a not so subtle 'accident'
}

int main()
{
    int array[5]{0,1,2,3,4};
    
    function(array,5,67);
    std::cout << array[0] << '\n';
    
    return 0;
}
Thank you for your kind reply, Duthomhas.

JLBorges wrote:
Using const proactively is a good idea ... but the const qualifier may be added to in the implementation of the function

Thanks a lot for your wise advice, JLBorges. I must confess I find it hard to remember all the ‘variation’ about const (that const int* is different form int* const, that const and constexpr are different, that I need to repeat const in header and source if it refers to the method, but not if it refers to a parameter...), but maybe one day I’ll get used to all those.
> that const int* is different form int* const

Read the declarations from right to left (mentally substitute 'pointer to' for the '*'):
1
2
3
4
5
6
const int * // pointer to const int
int const * // pointer to const int
int * const // const pointer to int
const int* const // const pointer to const int
const int * const * // pointer to const pointer to const int
const int ** const // const pointer to pointer to const int 


Using type alias would help:
1
2
3
4
5
6
7
8
using cint = const int ;
using pint = int* // pointer to int
using pcint = cint* // pointer to const int

pcint // pointer to const int
const pcint // const pointer to const int
pint // pointer to int
const pint // const pointer to int 



> I need to repeat const in header and source if it refers to the method, but not if it refers to a parameter.

The const specifier in a member function is part of the type of the function.
The top-level const qualification on a parameter passed by value is not part of the type of the function.

1
2
3
4
5
6
7
8
9
10
11
12
struct A
{
     
     int foo(int) ;
     int foo(int) const ; // this is not a redeclaration (it is an overload, it is a different function with the same name)

     int bar(int) ; 
     int bar( const int ) ; // this is a redeclaration of the same function
                            // *** error: class member cannot be redeclared - LLVM (clear and concise)
                            // *** error: 'int A::bar(int)': member function already defined or declared - Microsoft (already declared, but ok)
                            // *** error: 'int A::bar(int)' cannot be overloaded with 'int A::bar(int)' - GNU (slightly lame, but still ok) 
};
Last edited on
Topic archived. No new replies allowed.