Let's say I create a class called MyClass which contains a reference variable m_my_resource. This reference variable is essentially just a named alias associated with some other memory location.
MyClass
class MyClass
{
public:
MyClass(const MyResource& my_resource) :
m_my_resource(my_resource){}
private:
const MyResource& m_my_resource;
}
Now lets say I try to do the following:
main
{
MyClass my_class(utils::getMyResource());
//continue doing stuff
}
What exactly happens in this scenario? I have defined MyClass to only have a single constructor which takes in a reference (lvalue reference) to MyResource.
However, within my main function, I construct an instance of MyClass with a temporary object (rvalue). Why is my code able to compile? Doesn't my_class now contain a reference variable that is associated with some temporary memory location? Essentially the variable in which the reference variable was associated with has now 'died', what happens to the reference variable?
Furthermore, is this a case where I would want my class to have a constructor that accepts rvalue references?
Why is my code able to compile?
Just because your code compiles, doesn't mean that it will work correctly. Otherwise, every program in the world will be automatically bug-free, by the virtue of it successfully passing the compilation phase, and there wouldn't be any need for anyone to learn how to use a debugger.
Obviously, things don't work this way.
Doesn't my_class now contain a reference variable that is associated
with some temporary memory location?
Yes, it does.
Essentially the variable in which the reference variable was
associated with has now 'died', what happens to the reference
variable?
Nothing happens to your reference variable. It still exists. But referencing the object -- by that it means attempting to invoke its methods or access its members -- results in undefined behavior.
If getMyResource() returns a MyResource object, somewhere in getMyresource() you are allocating memory for the object (on the heap may be), so you have to release the allocated memory. For instance call the MyResource destructor for m_my_resource in the MyClass destructor. If you don't you are going to have memory leaks on your program. In C++ there is no garbage collector to release automatically allocated memory, you have to do it by yourself, but there is non apparent problem compiling, just executing, if memory leaks are a matter.
Related
What happens when a const reference to a a member of a temporary object is returned; What is the lifetime of that object;
E.g.
struct temp
{
T m_mine;
static temp make()
{
return temp();
}
};
T const & foo()
{
return temp::make().m_mine;
}
What is the behavior with c++98 and c++11?
The constness of the object or the referee type doesn't matter in this context: it's simply a return of a reference to an object that at that time has ceased to exist. Using the reference is then Undefined Behavior.
Likewise, if you bind a member reference to const, to an object, that does not prolong the life of the referee.
Object lifetime extension is only for the case of binding a local reference to an object, and only for the cases of reference to const object or rvalue reference.
The example code as it was at the time I wrote this, has several problems. Please only post real code (to the degree possible). And it should be pasted, not retyped.
(Also, since there is now at least 2 answers referring to the problems of the code, it's too late to correct it without possibly changing the context of the answers and thereby invalidating them. So it's important to get the code correct in the original posting. Worth keeping in mind for next SO question.)
Your code is incorrect in multiple accounts before it is even getting to compile:
there is at least a semicolon missing after the type declaration
the code uses the non-static member make() as if it is a static function
Once getting over that: the reference returned refers to a subobject of an object which is destroyed after the return statement is executed and before anything can get hold of it. That is, there is a stale reference return. Any access to this reference will result in undefined behavior. If you are lucky, the program crashes at this point. If you are unlucky it does something you like it to happen. For example it may "work" until the program is demonstrated to a client or an investor at which point it may decide to rather display insults.
Suppose I have an object Obj and a Set s. The Set is collecting const Obj& references in an array. How long will the actual Obj's be available:
{
Set s;
s.add(Obj(...));
s.add(Obj(...));
s.doWhateverWithTheObjs();
}
// after this it's guaranteed to not work anymore, if s was on the heap. Obj's will die with stack
I have not implemented that yet as I first want to confirm that this is actually going to work.
I know it won't work when the Set is on the heap and it's lifetime is longer then the lifetime of the caller (I made brackets to illustrate this).
What I don't know is whether the last method has still read access to the objects? Storing actual object by value in the Set won't work, because Obj is polymorph. If possible, I don't want to use pointers for usability reasons.
What I don't know is whether the last method has still read access to the objects?
The standard defines two cases in which the lifetime of a temporary is extended, at §12.2/4:
The first context is when a default constructor is called to initialize an element of an array. If the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any.
which is supposed to allow initializations of arrays. The second, which is of more concern is connected to references (at §12.2/5):
The second context is when a reference is bound to a temporary.118 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
As you can see, if a temporary object is bounded to a reference, the lifetime of the object extends to that of the reference. After the "except:" it is listed:
A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
This basically says, that no matter how you define the function body of add, if add's signature is T add(const Obj&) (with any T), the temporary object will be destroyed at the end of the call to that function. This means that in:
s.add(Obj(...));
The temporary object will be destroyed at the end of the function execution.
Therefore, for the above reasons: no. It won't still have read access to the object. You'll have a reference to a deallocated object.
Storing actual object by value in the Set won't work, because Obj is polymorph.
You can have a polymorphic behavior and still hold the objects. You can use for example an std::vector of std::unique_ptr<Obj>. The creation of a new object will happen like this:
vector.emplace_back(std::unique_ptr<Obj>(new Derived()));
and you will have a polymorphic vector that also store the values.
As long as you're inside the function, unless you replicate the object inside s.add (which, according to your question, you don't (Set is collecting const Obj& references in an array).
Second thought, not even during the function, since each Obj instance is allocated on the stack of the function only temporarily, during the call to s.add(Obj(...));.
In other words, don't do it this way (you must replicate the object inside s.add).
Supplemental:
There is nothing wrong with having const Obj& references in an array, but you gotta have the actual instances allocated somewhere, whether it's on the heap, or in the data-section (as global variables)... or on the stack of the calling function (as local variables) if you're not using them outside the function.
I've been programming in C++ for a while but certainly wouldn't call myself an expert. This question isn't being asked to solve a practical problem that I have, it's more about understanding what C++ is doing.
Imagine I have a function that expects a single paramater:
void doSomething(SomeClass& ref)
{
// do something interesting
}
(Note: the parameter is a reference to SomeClass) Then I call the function like this:
int main(int argc, char *argv[])
{
SomeClass a;
doSomething(a);
}
Why is this legal C++? The function is expecting a reference to SomeClass, but I'm passing it a statically allocated variable of type SomeClass. A reference is like a pointer no? If we were to replace the reference with a pointer the compiler complains. Why is the reference different to a pointer in this way, what's going on behind the scenes?
Sorry if this is a stupid question, it's just been buggin me!
I think you'd understand this better if you stopped thinking of references as being similar to pointers. I would say there are two reasons why this comparison is made:
References allow you to pass objects into functions to allow them to be modified. This was a popular use case of pointers in C.
The implementation of pointers and references is usually pretty much the same once it's compiled.
But they are different things. You could think about references as a way of giving a new name to an object. int& x = y; says that I want to give a new name to the object I currently refer to as y. This new name is x. Both of those identifies, x and y, both refer to the same object now.
This is why you pass the object itself as a reference. You are saying that you want the function to have its own identifier to refer the object that you are passing. If you don't put the ampersand in the parameter list, then the object will be copied into the function. This copying is often unnecessary.
Your code is incorrect - SomeClass a(); is a forward declaration of a function a returning a SomeClass instance - such a declaration is not valid at function scope.
Assuming you meant SomeClass a;:
A reference is quite similar to a pointer in most practical ways - the main difference is that you cannot legally have a reference to NULL, whereas you can have a pointer to NULL. As you've noticed, the syntax for pointers and references is different - you can't pass a pointer where a reference is expected.
If you think of a reference as a "pointer that can't be null and can't be made to point elsewhere" you're pretty much covered. You're passing something which refers to your local a instance - if doSomething modifies its parameter then it's really directly modifying your local a.
SomeClass a();
This is a function signature, not an object.
It should be
SomeClass a; // a is an object
Then your code is valid.
Why is this legal C++?
(assuming you fixed the previous point)
C++ standard say that if your function attribute is a reference, then you should provide an object that have a name (an l-value). So here, it's legal. If it was a const reference, you could even provide a temporary (an r-value, that have no name).
The function is expecting a reference
to SomeClass, but I'm passing it a
statically allocated variable of type
SomeClass.
It's expecting a reference to an non-const instance of SomeClass, that is what you did provide.
That instance is not static, it's just allocated on the stack. The allocation of an object have nothing to do with the way it can be manipulated, only the scope does. The way the object is alloced (on the stack like here, or on the heap by using new/delete) only tells the lifetime of the object. Even a static object could be passed in your function, as far as it's not const.
I think you're mixing some language concepts here...
A reference is like a pointer no?
No.
A reference is a "nickname" of an object. No more, no less.
Okay, in fact it is implemented as a pointer with special rules but it's not true in every use: the compiler is free to implement it in whatever way it want.
In case of a function attribute, it's often implemented as a pointer. But you don't have to even know about it.
For you, it's just the nickname of an object.
If we were to replace the reference
with a pointer the compiler complains.
Why is the reference different to a
pointer in this way, what's going on
behind the scenes?
I guess your first error did make things fuzzy for you?
You're not passing it "a statically allocated variable of type SomeClass", you're passing it a reference to a SomeClass object you created on the stack in main().
Your function
void doSomething(SomeClass& ref)
Causes a reference to a in main to be passed in. That's what & after the type in the parameter list does.
If you left out the &, then SomeClass's (a's) copy constructor would be called, and your function would get a new, local copy of the a object in main(); in that case anything you did to ref in the function wouldn't be seen back in main()
Perhaps your confusion arises from the fact that if you have two functions:
void doThingA(int a) {
a=23;
}
void doThingB(int &a) {
a=23;
}
The calls to them look the same, but are in fact very different:
int a=10;
doThingA(a);
doThingB(a);
The first case, doThingA(int), creates a completely new variable with the value 10, assignes 23 to it and returns. The original variable in the caller remains unchanged. In the second case, doThingB(int&), where the variable is passed by reference, a new variable is create with the same address as the variable passed in. This is what people mean when they say passing by reference is like passing by pointer. Because both variables share the same address (occupy the memory location) when doThingB(int&) changes the value passed in, the variable in the caller is also changed.
I like to think of it as passing pointer without all that annoying pointer syntax. Having said that though, I find functions that modify variables passed by reference to be confusing, and I almost never do it. I would either pass by const reference
void doThingB(const int &a);
or, if I want to modify the value, explicitly pass a pointer.
void doThingB(int *a);
Reference is not a pointer. You simply pass parameters as "by value" and use-it . Under the hood only a pointer will be used, but this is just under the hood.
A reference is nothing at all like a pointer, it is an alias - a new name - for some other object. That is one reason for having both!
Consider this:
Someclass a;
Someclass& b = a;
Someclass& c = a;
Here we first create an object a, and then we say that b and c are other names for the same object. Nothing new is created, just two additional names.
When b or c is a parameter to a function, the alias for a is made available inside the function, and you can use it to refer to the actual object.
It is that simple! You don't have to jump through any loops with &, *, or -> like when using pointers.
Though the question has been already answered adequately, I can't resist sharing few more words on the related language feature of "References in C++".
As C programmers, we have two options available when passing variables to functions:
Pass the value of the variable (creating a new copy)
Pass the pointer to the variable.
When it comes to C++, we are usually dealing with objects. Copying such objects on each function call that needs to work on that object is not recommended due to space (and also speed) considerations. There are benefits involved with passing the variable address (via the pointer approach), and though we can make the pointer 'const' to avoid any changes through the pointer, the syntax with pointers is rather clumsy (miss the dereference operator at a place or two and end up spending hours debugging!).
C++, in providing 'references', packages the best of both options:
The reference can be understood to be as good as passing the address
The syntax to use the reference is the same as working on the variable itself.
The reference would always point to 'something'. Hence no 'null-pointer' exceptions.
Additionally, if we make the reference 'const', we disallow any changes to the original variable.
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 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 :).
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.
No. That's why you need a ~ClassB destructor if ClassB is responsible for the storage of ref which it might not be.
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.
No; references are merely an alternate syntax for pointers. The value they reference won't be modified if the reference is deallocated.
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.
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.
this snippet of code is given me headache. Personally, I would like to use reference as they are neater compared to pointer, so I tried this:
include "SomeClass.h"
class FooBar
{
private:
SomeClass& member_;
public:
FooBar() : member_(SomeClass()) { };
}
I have read that you need to assign a temp variable to a class member reference, so in this case I create a dummy SomeClass() (I'm not sure if I am doing it right here. I tried it with and without specifying a default constructor). However, it does not compile in VS 2005, saying that member_ cannot be initialised.
How should I be doing this?
Thanks in advance!
You can only bind a temp to a const reference. So if you change it to
const SomeClass& member_;
you'll be fine.
You probably don't want this, though; you either should just declare member_ as a value, not reference, or, if you want it as a reference, you probably want to pass in a reference to your constructor, like
FooBar(SomeClass& sc) : member_(sc) { };
1) References can not be changed to point to another object after it is initialized.
Do you really need this behavior?
2) When you initialize reference with temporary object, after this temp. object is out of scope your reference is invalid.
That's why your code is incorrect. And you have useless member now. I'd recommend to think about two alternatives
a) Consider using pointer instead of reference.
b) Change you constructor to something like this:
MyClass(type & a):membmer_(a){...}
According to the standard you can not store a non-const reference to a temporary variable. When you create SomeClass() object in the constructor it is a temporary object and you are trying to store it as a non-const reference. BTW, I don't think references are required here. You can simply store it as SomeClass member_;
Do you definitely not want the reference to be set in the constructor? i.e.
FooBar(SomeClass& sc) : member_(sc) {};
If not, and you are going to set it later, then I think a pointer is your best option, despite not being as "neat".
See here.
Does this member need to be a pointer or a reference? Though your interface may be simplified, it doesn't look like you intend to pass an instance of SomeClass to the constructor of FooBar. This is where the reference is useful as you guarantee that the instance used by the class is the same as the one given to it.
If your intent is to encapsulate SomeClass in FooBar, then the following will suffice.
include "SomeClass.h"
class FooBar
{
private:
SomeClass member_;
// ... rest of your implementation ...
// default ctor/dtor is sufficient.
}
This code will instantiate a SomeClass instance when FooBar is instantiated. The class destructor (generated by the compiler) will take care of releasing the stack memory that is allocated for member_.
Short answer: As Jesse pointed out, you probably want to use a value member or a pointer, but not a reference in this specific example.
Long answer: The memory model of C++ is more like C's and less like Java's. Objects can exist
on the stack. This is the case for parameters and local variables.
on the heap. This is the case for all objects created with new.
in the data segment. These are your global variables.
inside other objects as value members.
As opposed to this, in Java, except for primitive types and pointers (in Java called references), all objects are created with new and exist on the stack. This simpler memory model is sufficient for Java since it has garbage collector, which automatically destroys unused objects.
Standard C++ does not have a garbage collector. An object is deleted in the following circumstances:
a stack-based object is deleted when "it goes out of scope",
a global object is deleted when the application terminates,
objects contained in other objects are deleted when the containing object is deleted, but
objects on the heap must be manually deleted by the developer using delete.
Because this manual memory management is error prone, you usually define strong ownership policies between the objects in your C++-application.
Coming back to your question, you want to make sure that you can access your member_ as long as your FooBar-object exists. So if member_ is not something like FooBar's owner or another in a similar way closely related object, which is guaranteed to exist as long as the FooBar-object exists, you probably do not want to use a reference.
In your example, I would use
a value member if I think of FooBar containing member_,
a pointer otherwise.