0

This question already has an answer here:

In C++, we have the option to pass by reference or pass by value.

The client code does not need to know which one a parent function uses; that is, int func(int param) and int func(int &param) are called in exactly the same manner from the client code. Isn't this dangerous?

If I'm writing code on the client side, I don't know which of the variables I pass to a function might be changed and which I can expect to remain the same without an explicit knowledge of the parent function declaration. What is the advantage of doing it this way versus explicitly expecting a pointer (e.g., int func(int *param), which would then be called func(&param);)?

When you have to have a pointer, it's easy enough for the client to know which values may be modified - the ones that have an & in front. Alternatively, why not have everything be pass-by-reference, so that there is no guess-work of "Can this function change this value?" The answer is universally yes.

marked as duplicate by gnat, Bart van Ingen Schenau, user53019, user40980, Robert Harvey Jul 10 '14 at 0:13

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    If the function takes a const reference, it can't change the input. But that seems to be neither here nor there; how will you know the function won't have other side effects? If this sort of thing bothers you, C++ is probably not the language for you. – Doval Jul 9 '14 at 12:49
  • no more so than C# - compare passing a struct to a class. One is a value type, the other a reference so you change the data in one, you change the data of a copy in the other. Other languages have similar issues, you just have to be careful, take your time, and know what you're doing. – gbjbaanb Jul 9 '14 at 12:51
  • The only real danger is in calling a function and not understanding what it's going to do with the arguments. – Blrfl Jul 9 '14 at 12:56
  • 1
    @wolfPack88: Note that pass-by-reference was added to C++ to make operator overloading possible for operators that modify an operand (like operator++). – Bart van Ingen Schenau Jul 9 '14 at 13:24
  • 1
    @wolfPack88: The goal was to allow classes that are a drop-in replacement for the basic types. This means that the user must not need to use different syntax for invoking a built-in or overloaded operator. – Bart van Ingen Schenau Jul 9 '14 at 13:41
2

If I'm writing code on the client side, I don't know which of the variables I pass to a function might be changed and which I can expect to remain the same without an explicit knowledge of the parent function declaration.

This is as it should be. When you call an API, you should know what you are calling and why. You should also know what the function does and what it's side effects are (and preconditions and postconditions as well).

What is the advantage of doing it this way versus explicitly expecting a pointer (e.g., int func(int *param), which would then be called func(&param);)?

I will assume that "doing it this way" means "passing by reference".

It seems to me you make the association "received by pointer = may be changed". This is incorrect.

Here are two scenarios when passing by reference/pointer is prefered over the alternative:

  • operators:

    class EvenInteger { int value; public: /*...*/ }; // 0, 2, 4, 6, ...
    
    EvenInteger operator +(const EvenInteger& x, const EvenInteger&y);
    

    Here, passing by reference would disble the operator for temporary values, passing by pointer would result in client code like this:

    EvenInteger a{0}, b{122};
    auto c = &a + &b; // addition by address imposed if operator received pointers
    
  • instance observer (naturally pass 'this' as an argument):

    class Collection // collection/sequence of arbitrary objects of type Obj
    {
    public:
        class InterestingIterator {
            Collection* parent;
            InterestingIterator(Collection* c); // accessible by Collection
        public:
            // ...
        }
    
        InterestingIterator begin() { return InterestingIterator{this}; }
    };
    

    The implementation of begin, naturally receives a this pointer, without implying it is in any way a return value. Writing the iterator to receive a reference imposes the *this construct on client code.

As a rule, the interface of an API should tell you this:

void f(int x); // makes own copy of x, doesn't return/alter value
void f(int& x); // _may_ alter value (check docs)
void f(int* x); // _may_ alter value, or populate it with a return (check docs)
void f(const int& x); // observer of x
void f(int* const x); // _may_ alter value pointed by x, but not the address
void f(const int* x); // _may_ alter address, but not the pointed value
void f(const int* const x); // observer of value and address

As you can see, you should (always) rely on an API's documentation. If you rely on a function signature, it can only tell you when it doesn't alter it's received parameters, and you see that through const, not through the parameter type (address/reference/etc).

This also implies that you should always write documentation for your APIs.

0

The differences between references and pointers have been extensively discussed, sometimes even here. That discussion probably shouldn't be re-started.

But the other question - "Why not have everything as X or Y?" is easily answered. C++ gives you both options as a matter of principle, because you might want to use X, but you also might want to use Y.

In such cases the language virtually always offers both on the principle that if one of the two allows a solution that is even slightly better, more effective etc., then the language must contain both. Recall that you can even write your own class-specific memory allocators and deallocators. The language designers are firmly of the opinion that at least some of their users will be able to build a better special-purpose allocator than they could build into the compiler, so they mustn't do anything that prevents this. This is part of the reason why C++ has such an extraordinarily rich set of interacting features, even when they are only slightly different.

  • I did not ask about the difference between references and pointers; I have seen the question you linked and others before. That isn't relevant here. The only question I asked is "the other question", as you mentioned. And your answer, unfortunately, doesn't help me in the slightest. "you might want to use X, but you also might want to use Y": I knew that, otherwise it wouldn't make any sense to have them in the language. In what instance does one or the other matter? According to the answers to the question you yourself linked to, it shouldn't matter. So again, why have both? – wolfPack88 Jul 9 '14 at 12:56
  • "Why have both?" Because there are differences between the two, and C++ lets you decide which one fits your situation best. See the link for the differences. – Sjoerd Jul 9 '14 at 14:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.