Question about arguments of methods in C++.

What's the difference between these two arguments?

void example(Number *obj)
I believe in this first example i'm passing a copy of a variable which contains an memory address. In another words i'm passing a copy of a memory address.

void example(Number &obj)
But in this case i'm not sure what i'm passing?
Hi,

The second one is a reference, which is preferred because a reference always has to refer to a variable, as opposed to a pointer which can be made to point at anything - including nothing (nullptr)

Both code snippets achieve the same thing: there is potential for the variable in the outer scope (the function that called the example function) to be changed by the function. By passing parameters this way (non const), one is stating that intent, otherwise the parameter should be const.

Any class (A STL class,or one of your own) should be passed by reference, otherwise you get a copy.

References and pointers are closely related, the standard doesn't say how things are implemented, but I imagine that references are const pointers.
Last edited on
@TheIdeasMan,

a reference always has to refer to a variable, as opposed to a pointer which can be made to point at anything - including nothing (nullptr)

What about references that references a variable out of scope. Does it not point to anything or nothing ?
What about references that references a variable out of scope. Does it not point to anything or nothing ?
A reference doesn't point to anything. A reference is another name for the exact same object.

Accessing a reference to an object that has fallen out of scope is undefined behaviour. The C++ language makes no demands on what will happen.
What about references that references a variable out of scope. Does it not point to anything or nothing ?


Isn't that a compiler error? The thing is that if it references a variable out of scope, it no longer refers to something. I should have known to mention that, in any case :+)
The compiler is free to do whatever it likes in this case, and it is by definition not an error. That's undefined behaviour for you.
Moschops wrote:
Accessing a reference to an object that has fallen out of scope is undefined behaviour. The C++ language makes no demands on what will happen.


Ok, thanks for clearing that up :+)

I wonder why it can't be an error: It's obviously a problem?

Also, we already have copy elision and move semantics when returning an object from a function, I find it interesting that the compiler can't do one of those if trying to return a local reference: why can't the local reference be treated like an xvalue?

A final question: The standard doesn't mandate how something should be implemented, how else might one implement a reference if it wasn't a const pointer?
I wouldn't be surprised if leaving it undefined allowed compiler writers to skip various checks and allows various optimisations.

If you return a local or temporary as a const reference, its lifetime is extended until the reference goes out of scope, but that's specifically mentioned in the standard.
http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/


I could imagine implementing a reference along these lines, in this very simple case:

1
2
3
int x = 5;
int& z = x;
z++;

compiling to effectively the same as
1
2
int x = 5;
x++;


No pointers. z is just another name for x, so just use x. This is, of course, a simple contrived case, but it would work fine here.

Last edited on
@Moschops

Thanks for your excellent answer, the const ref is especially good :+)

Cheers !!
TheIdeasMan
The second one is a reference...


1- So, in another words, is a copy of an address of a pointer variable, and this pointer variable contains an address of something?

2- This reference is always to a pointer variable?
Last edited on
1- So, in another words, is a copy of an address of a pointer variable, and this pointer variable contains an address of something?

No, not at all. It's not a pointer. It's a reference.

When you pass a parameter normally, the function gets a copy of that parameter to work on. When you pass a parameter by reference, the function does not get a copy; it works on the original object. Any changes the function makes to that object persist after the function finishes, because it wasn't working on a copy; it was working on the original object.

2- This reference is always to a pointer variable?

No. This reference is not referring to a pointer.
Last edited on
Moschops
No, not at all. It's not a pointer. It's a...


But in the follwoing code i'm passing the reference to "increment", don't i?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using namespace std;

void increment(int *n) {
	*n += 1;
}

int main( ) {
	int val = 0;
	
	increment( &val );
	cout << "new val: " << val << endl;

	return 0;
}
The confusing thing is that sometimes & means "reference to" and sometimes it means "address of" and sometimes it means "bit-wise and". At line 12, &val is the address of val.

The second one is a reference, which is preferred because a reference always has to refer to a variable, as opposed to a pointer which can be made to point at anything - including nothing
That's the test I always use when deciding whether an argument should be a reference or a pointer. If it's okay to pass no argument at all, then use a pointer so the caller can pass nullptr. If there should always be an object then use a reference.

A final question: The standard doesn't mandate how something should be implemented, how else might one implement a reference if it wasn't a const pointer?

Consider:
1
2
3
4
5
int f(int a)
{
    int &b(a);
    return a+b;
}

You could access the reference b using the same code you'd use to access a, which might involve an offset from the stack. When I compile this with g++ and optimizations turned on, it puts a (and b) is register rcx and the entire function becomes two instructions.
1
2
        leal    (%rcx,%rcx), %eax
        ret

why can't the local reference be treated like an xvalue?

Do you mean that caller should destroy the value when it goes out of scope? Consider this:
1
2
3
4
5
6
7
int &f(bool b)
{
    static int i1;
    int i2;
    if (b) return i1;  // caller should not destroy returned ref
    else return i2;    // caller should destroy returned ref
}

@robgeek

I hope you don't mind this discussion continuing in this fashion: I have kinda derailed your topic a bit; but hopefully you already have your answer. I can start a new Topic if you want :+)

@dhayden

Thanks for your reply, I understand the reference / alias part now.

Do you mean that caller should destroy the value when it goes out of scope?


I guess all the following argument / discussion is a bit academic: the answer is to return a const reference (or return the object), but here goes anyway .....

I hadn't thought of static variables, I wonder if that is the reason for an almost blanket rule?

As the link the Moschops kindly provided says that the scope is extended when a const reference is returned, it seems it can be done in that situation. The rule is:

gotw wrote:
A2: No.

The "const" is important. The first line is an error and the code won’t compile portably with this reference to non-const, because f() returns a temporary object (i.e., rvalue) and only lvalues can be bound to references to non-const.


Emphasis mine. I wonder why that is the rule? Also, the xvalue has a name: that makes it a lvalue doesn't it? This article was written in 2008, before the more refined concepts of lvalue, xvalue, prvalue and the categories of glvalue and rvalue were introduced, although I understand this is still the rule.

So if the scope is extended for const reference, and we can have RVO, copy elision, move semantics for an object: why not for a non const reference ? Moschops was saying he wouldn't be surprised if that it allows the compiler to skip some checks and allow optimisations, it's just that RVO etcetera are optimisations.

Maybe the const reference is an elegant solution that avoids the static variable problem, but the corollary is that local non const refs can't be returned ? I haven't seen it described in this way.
But in the follwoing code i'm passing the reference to "increment", don't i?


This has been answered already, but in the interests of a really simple answer:

No. In that code, you're passing a pointer.
Last edited on
Topic archived. No new replies allowed.