Are reference attributes destroyed when class is destroyed in C++?
Asked Answered
W

7

24

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?

Warranty answered 25/5, 2010 at 20:28 Comment(1)
What exactly do you mean by "destroyed"? Just call the destructor, or also release the memory? Anyway, neither of those things happen :)Impenetrable
B
22

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 :).

Bloodline answered 25/5, 2010 at 20:33 Comment(0)
S
15

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.

Seriema answered 25/5, 2010 at 20:52 Comment(1)
+1 for your "on the other hand". I didn't realize that const references can affect an objects lifetime.Quickstep
N
2

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

Non answered 25/5, 2010 at 20:31 Comment(1)
in the best of all possible worlds ;)Non
F
1

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.

Fuse answered 25/5, 2010 at 20:54 Comment(0)
R
0

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

Rosenberry answered 25/5, 2010 at 20:30 Comment(39)
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."Hudgens
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++.Rosenberry
@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.Hudgens
@GMan: write two applications, one with pointers and the other with references. diff their assembly. You'll notice that they are identical.Rosenberry
@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.)Hudgens
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#.Rosenberry
That's a whole different topic. How you categorize languages has little (nothing?) to do with the languages themselves.Hudgens
const int& i = Function(); const int* p = &Function(); If Function() yields a temporary, how do those two lines differ in functionality, and how is this possible if references are identical to pointers?Enabling
@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.Rosenberry
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.Dextral
@John: How can only one of those two statements be illegal if pointers and references are the same?Enabling
@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.Rosenberry
@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".Dextral
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.Enabling
@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 = &Function();, it's wrong.Rosenberry
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.Enabling
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.Rosenberry
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?Enabling
Example: int a = 4; int &b = a;. 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.Enceinte
@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.Rosenberry
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.Enceinte
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.Enabling
Another example: Foo f() { return Foo(); }, then const Foo &a = f(); const Foo *b = &f(); ... 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.Enceinte
@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.Enceinte
Also, notice how sizeof(char&) is 1 and not sizeof(char*). Also, a type like char& Class::* does not exist (member pointer to references don't exist). The language has a clear separation of these concepts.Dextral
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.Rosenberry
@Steve: What bizarre compiler do you use which allows using a temporary as an rvalue?Rosenberry
@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.Enceinte
@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 :-pEnceinte
@Steve: I already made that argument too. This is truly a waste of time.Enabling
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.Enceinte
...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.Enceinte
"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).Rosenberry
Ah, GCC (perhaps unhelpfully) does a different thing for class types than it does for int.Enceinte
@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.Enceinte
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.Enceinte
"associative, commutative binary operator" - what was I saying? I mean associative, invertible binary operator! Nobody ever claimed The Beatles were Abelian...Enceinte
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 ;-)Enceinte
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.Rosenberry
F
0

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.

Fibril answered 25/5, 2010 at 20:43 Comment(0)
Q
-1

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.

Quickstep answered 25/5, 2010 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.