views:

152

answers:

7

Suppose I have a C++ class with an attribute that is a reference:

class ClassB {
    ClassA &ref;
public:
    ClassB(ClassA &_ref);
}

Of course, the constructor is defined this way:

ClassB::ClassB(ClassA &_ref) : ref(_ref) { /* ... */ }

My question is: When an instance of class 'ClassB' is destroyed, is the object referenced by 'ClassB::ref' also destroyed?

A: 

No; references are merely an alternate syntax for pointers. The value they reference won't be modified if the reference is deallocated.

John Millikin
References are not alternate syntax for pointers. They are aliases to other objects. You could say "in the same way pointers don't delete what they point to, references to not destruct what they alias."
GMan
A pointer is an address in memory, dereferenced by the `*` or `->` operators. A reference is an address in memory, dereferenced by the `.` operator. If you don't understand how pointers and references are fundamentally identical, you've got no business working in C++.
John Millikin
@John: If you'd like to point me to the location in the standard where it says "References are alternate syntax for pointers", be my guest.
GMan
@GMan: write two applications, one with pointers and the other with references. diff their assembly. You'll notice that they are identical.
John Millikin
@John: Who said anything about a particular compilers output? We're talking about C++, the language. So I ask again: Where, in the language standard, does it state references are alternate syntax for pointers? (Yeah, references are most easily *implemented* with pointers, but implementation has nothing to do with the *language*.)
GMan
Man, I hate it when people play that game with C++. Get over it -- C++, like C, is nothing more than a cross-platform macro language for assembly. You can't reason about it based on the standard, because in many (most?) cases, the behavior of compilers is much *much* more important than whatever inanity the standard contains.If you'd like to program in some perfect abstract system, use Java or C#.
John Millikin
That's a whole different topic. How you categorize languages has little (nothing?) to do with the languages themselves.
GMan
`const int const int* p = ` If `Function()` yields a temporary, how do those two lines differ in functionality, and how is this possible if references are identical to pointers?
Dennis Zickefoose
@Dennis: The second ought to be illegal -- if your compiler allows it, use a better compiler. The first will implicitly copy the value before constructing the reference.
John Millikin
If references were an alternate syntax for pointers, you could get their address (every pointer has an own address). But you can't. So i can't quite see the pointer there.
Johannes Schaub - litb
@John: How can only one of those two statements be illegal if pointers and references are the same?
Dennis Zickefoose
@Johannes: references have an address (again, look at the assembly). There's simply no syntax to retrieve it, but you can find it with a debugger. @Dennis: Because the standard specifies that const references can be used to refer to temporary variables. References are still pointers, as the reference value is a memory location.
John Millikin
@John you are mixing the levels. By that argument you need to also say that pointers are just integers (and that pointers are "alternate syntax" for integers), because "at the assembly"... There are *two* pointer meanings. On the language there is a meaning, and outside the language ("at the assembly") there is another meaning. You can't just say that references (which are not pointers on their level) are pointers *without explicitly saying on what level*, if you steer away from their level. The same thing about "address".
Johannes Schaub - litb
I thought the standard didn't matter? I'm very confused. For the record, gcc compiles those two lines quite happily, but the behavior of the two statements is quite different, despite your repeated assurance that pointers and references are identical.
Dennis Zickefoose
@Johannes: Pointers *are* just alternate syntax for integers, usually 16-, 32-, or 64-bit depending on platform. @Dennis: when the standard doesn't specify some behavior, then it's important to know how compilers will implement it. If your compiler accepts `const int* p = `, it's wrong.
John Millikin
But again: *why* is it wrong? If pointers and references are the same thing, why can you take a const reference to a temporary, but not take the address of one? The answer is because, at a high level, references are not pointers. Temporaries need not have an address, but you can still reference one. But without an address, you can not create a pointer.
Dennis Zickefoose
You're being deliberately obtuse. You can create a const reference to a temporary because the temporary will be implicitly copied to the stack. This is no different from allocating the variable on the stack, and then placing its address in a pointer. Temporaries do have an address, because all values have an address.
John Millikin
Why must it be copied to the stack? Why can it not exist in a register, for instance? If it does have to be copied to the stack, why can you not take the address of that stack location without creating *another* copy of it first?
Dennis Zickefoose
Example: `int a = 4; int `. `b` is not a pointer. It's not syntactic sugar over a pointer. It's another name for the same object which `a` is a name for. *If* the compiler implements it by taking a pointer to `a` then OK, that's how it implements it, but there's no particular reason in this example to think it should implement it that way, other than because in *your* head (not in the language spec, and quite possibly not in your compiler-writer's head), you have failed to form a conceptual model of references distinct from your conceptual model of pointers.
Steve Jessop
@Dennis: registers are limited to 64 bits or so; structs and class instances can't be stored in them. @Steve: C++ doesn't have "objects", it has structs with a bit of extra syntax to hide the vtable implementation. Saying "a reference is an alias" is *completely useless*, because that doesn't tell you anything about how it will be implemented in the assembly.
John Millikin
Replacing "object" in my comment with "struct with a bit of extra syntax to hide the vtable implementation" leaves the sense intact and correct. Your refusal to use the C and C++ jargon meaning of the word "object" has nothing to do with what is actually going on either in the languages or in the implementations. If this is intended just to be pointless posturing over terminology, please do say so. If you want to discuss similarities in between pointers and references, that can happen, but only if you actually have an interest, instead of some axe to grind over the language in the standard.
Steve Jessop
Why not? I can think of dozens of structs and classes that can easily fit in a 32-bit register. Further, my example involved temporary integers, which generally fit quite easily in a register. As for your response to Steve, saying references are pointers doesn't tell you anything about how it will be implemented in the assembly either, as his example proves. Compile that; if `b` even *exists* in the resultant binary, something is horribly wrong.
Dennis Zickefoose
Another example: `Foo f() { return Foo(); }`, then `const Foo const Foo *b = ... some more code`. Contrary to your earlier assertion that code using references is exactly the same as code using pointers, the temporary "struct with a bit etc" which is the return value of f() in each case is destructed at different times. References are not pointers (although as you incisively point out, they are implemented using them), and they don't (always) behave like pointers either.
Steve Jessop
@Dennis: actually, with GCC, in my example the emitted code in fact is the same for `b` or for a pointer to `a`. At -O0, a pointer is taken for either one. At -O1, both are omitted (assuming you don't later take the address of the pointer, of course). But you don't need to know if they're the same or not to understand the concepts. If John insists that C++ (or for that matter, any compiled language) fundamentally "is" not an abstraction, but two things "are the same" if his compiler outputs the same code, then a reference and a pointer to `a` in this case are the same. But he's filibustering.
Steve Jessop
Johannes Schaub - litb
I refuse to use C++ jargon in this case because it's wrong. "object" has a clearly defined meaning, which is not present in either C or C++. @Steve: if you can come up with an example in which a reference is not the same as a pointer when compiled, then I'll concede the point. I hold that for C and C++, being fundamentally low-level languages, it's more important to understand what the compiler will generate than what the standard claims. Especially for C++, which has a history of severe bugs in all major compilers.
John Millikin
@Steve: What bizarre compiler do you use which allows using a temporary as an rvalue?
John Millikin
@John: "jargon" means an alternative meaning in a particular context. As a mathematician, I would love to claim that The Beatles were not really a pop "group", because they didn't have an associative, commutative binary operator. However, I cannot do so. Mathematicians do not own the word "group", and OOP does not own the word "object". Where emitted code differs: anything based on Dennis's and my example with a const ref extending object life. OK, so you think one of the cases "should" not be valid, but it is valid. GCC gives a warning. Not just emitted code is different, behaviour is.
Steve Jessop
@John: lvalue, you mean? Dunno, I might have to roll back my claim that the code is valid. But if it's not valid, I can get you the other way - earlier you said the standard was irrelevant, what matters is what compilers do. Now you're claiming that if my compiler compiles it, but the standard says it's not valid, then you're still right :-p
Steve Jessop
John Millikin
@Steve: I already made that argument too. This is truly a waste of time.
Dennis Zickefoose
Hmm, I get "warning: taking address of a temporary". g++ 4.3.4. Maybe you have a more recent, stricter version, or maybe we're using subtly different code.
Steve Jessop
...Comeau rejects the code I was using. So all the example shows is that references can do things which pointers cannot do. It doesn't show that, for the things they both do, they do them differently. Not sure whether that means references "are pointers" or not.
Steve Jessop
I'm using this code < http://pastebin.com/UUdeERAm >, with g++ 4.1.2.
John Millikin
"So all the example shows is that references can do things which pointers cannot do" -- how so? The code example you've provided has nothing to do with the capabilities of pointers vs references. C++ allows temporaries to be copied using some particular syntax, but the declared reference still acts like any other (and just like pointers).
John Millikin
Ah, GCC (perhaps unhelpfully) does a different thing for class types than it does for `int`.
Steve Jessop
@John: well, in the reference case the initialisation of a reference using a temporary in effect promotes the temporary to a local-scope object. I don't know why you say the temporary is "copied" because of that - if a temporary return value is used in any way, then presumably it will be put on the caller's stack (either constructed there or copied there according to whether RVO is applied). It's not then copied again just because of being bound to the reference. This kind of reference is more "really" an automatic variable (of type Foo) than "really" a pointer.
Steve Jessop
Compare with `const Foo a = f();`, where `a` is (sort of) defined to be a copy of the temporary return value of `f()`. "Sort of" because copy elision is permitted there too, so `a` may or may not actually be a copy, since the temporary may or may not be created in the first place. But the upper limit on the number of copies is one greater than if the function were called without using the return value. With the const reference, the upper limit doesn't go up. I confess I've strayed off the original question, though, which was about a member reference, and those references can't do this trick.
Steve Jessop
"associative, commutative binary operator" - what was I saying? I mean associative, invertible binary operator! Nobody ever claimed The Beatles were Abelian...
Steve Jessop
Btw, you said earlier that programming in Java and C# is using a perfect abstract system. Is there some sense in which Java references "are not pointers" but C++ references "are pointers"? I always thought that Java very nearly managed to keep a straight face, right up to the point where they named `NullPointerException`, and gave the game away ;-)
Steve Jessop
That was a poor example, sorry; Java and C# both use pointers, though they're careful to remove the useful features (eg, pointer arithmetic). What I meant was that C and C++ depend so much on architecture-specific behavior that it's not reasonable to use them without understanding exactly how each feature is implemented.
John Millikin
I can't believe you still discuss this silly topic.
Johannes Schaub - litb
+2  A: 

No. That's why you need a ~ClassB destructor if ClassB is responsible for the storage of ref which it might not be.

msw
"which is bloody unlikely".
MSalters
in the best of all possible worlds ;)
msw
A: 

I don't have the C++ spec on hand, but my guess is "No".

Pointers aren't deleted automatically when an object is destroyed, I see no reason that a reference should be different. Plus, having the reference automatically destroyed would be ripe for interesting bugs.

A. Levy
+7  A: 

A reference is nothing but an alias for a variable, the alias gets destructed, not the actual variable. You could consider it some kind of pointer, but there are reasons to refrain from this kind of (evil) thoughts :).

Pieter
A: 

If you want it to be destroyed, you will have to encapsulate it (normally done via "smart" pointers, like std::shared_ptr or std::unique_ptr), that will automatically release the memory in an appropriate fashion on destruction of B. In-language references have no memory freeing behaviour associated with them, except the actual memory of the reference itself, as opposed to the referred.

You will have to build and understand your own memory model. People typically use shared_ptr and reference counting for basic uses.

DeadMG
+3  A: 

No. Reference members do not affect the lifetime of whatever they point to. This means the thing they alias may have a longer or a shorter lifetime than that of the reference.

On the other hand, const references can affect the lifetime of what they point to if they point to a temporary.

In your case it does not.

MSN
+1 for your "on the other hand". I didn't realize that const references can affect an objects lifetime.
A. Levy
+1  A: 

When an object is eliminated in C++, its memory is deallocated and thus everything that was embedded in it (such as member variables) is lost as well.

In the case of a pointer, the pointer is a member variable that contains an address, so the address is "destroyed" but the referenced object, if any, is not.

In the case of a reference member, the address is destroyed, but the target is not affected.

A class may define a destructor that could define special behaviors. One common such behavior is to invoke cleanup operations on members (if any), and to deallocate memory that was dynamically allocated earlier. Here, however, you already got an object so you should not be the one deallocating it.

Uri