Hold a unique pointer reference to a unique pointer reference - c++

Here is a program that represents my conceptual problem:
int main()
{
unique_ptr<int> a = make_unique(5);
{
unique_ptr<int>& b = a;
}
printf("%d",*a);
}
Is a the owner of the object?
When a goes out of scope, does the value of somepointer get destroyed?
By running the above code I see it doesn't but I don't understand why. What exactly happens in the assignment?

a remains the owner of the object this entire time.
In C++, placing & before a variable name creates a reference, which is like an implicit pointer. Since you've declared b as a reference, there is only ever one unique_pointer in this code. a is the unique_pointer itself, and the reference b points to that pointer.
This is the reason the unique_pointer is not destroyed when the block containing b is exited; b never owned the resource because b was never a unique_pointer to begin with, only a reference to one.
See learncpp for a full lesson on references.

The assignment to b is simply a reference, it has no bearing on the object lifetime of a. Imagine instead that you had passed a to a function taking a unique_ptr<int> &, you wouldn't expect the reference to alter the lifetime of a in that case, why would you do so here?

Related

Reference Reassignment

I have a general C++ question.
Lets say I have this code:
int& GetInt()
{
int* num = new int();
return *num;
}
int numCopy = GetInt();
In this situation, what happens to the returned reference? This example uses a simple data structure so it doesn't really matter, but in cases where the returned data is more complex, would assigning a variable to a heap-allocated variable reference like this copy the data over to numCopy completely, or would numCopy become another reference to the original num?
In this situation, what happens to the returned reference?
It goes out of scope at the end of the full expression and you have now leaked the memory you acquired in GetInt. You've made a copy of the value the reference refers to, but the original object, and the memory it occupies are no longer accessible.
If you had
int& foo = GetInt();
then you could later on do
delete &foo;
to not have a memory leak, but this is still bad practice.
or would numCopy become another reference to the original num?
You only ever get a reference if you specifically ask for it.
int numCopy = GetInt();
says numCopy is an int, not a int&, so it will not be a reference. C++ has what is called value semantics, which basically means unless you ask for a reference, the object you create is it's own object that is independent from all other objects.

shared pointer and raw pointer lifetime

Could someone explain simply the reason why this does not work:
std::shared_pointer<Bar> getSharedPointer() {
return std::make_shared<Bar>();
}
...
auto foo = getSharedPointer().get();
Apparently using the raw pointer foo will cause a segfault because the lifetime of the shared pointer returned by getSharedPointer() will have run out. Somehow I would expect it to last until the end of its scope (like whatever block it is inside).
Is this correct and are there any analogous examples to this situation?
For getSharedPointer().get();, getSharedPointer() returns a temporary std::shared_ptr which will be destroyed after the expression immediately, and the pointer managed by it will be deleted too. After that foo will become dangled, any dereference on it causes UB.
auto foo = getSharedPointer().get();
// foo have become dangled from here
You could use a named variable instead:
auto spb = getSharedPointer();
auto foo = spb.get();
// It's fine to use foo now, but still need to note its lifetime
// because spb will be destroyed when get out of its scope
// and the pointer being managed will be deleted too
auto foo = getSharedPointer().get();
Whenever a function returns a type that is not a reference, the result of calling the function is an rvalue. Also, because the function getSharedPointer() returns a class type, the result is a temporary object.
The lifetime of that temporary object is defined as the end of the evaluation of the outermost expression, here getSharedPointer().get(). As soon as the foo variable is initialized, the owning smart pointer is destroyed; when the last shared_ptr owning that object is destroyed, the object is deleted.
Here getSharedPointer() always returns shared_ptr that doesn't share the managed object (use_count() is 1), so when that copy of the last shared_ptr is destroyed, the object is destroyed and the pointer to the object is invalid.
(I am not sure why you are returning a shared_ptr and not a unique_ptr here.)
The proper use of a smart pointer, or any class that "owns" (controls the lifetime of) other resources (resources that you are still allowed to access directly), is to keep the "smart" pointer/owner alive as long as you need to access the ressource.
So the "smart" pointer (owning object) needs to be named. Also, I am not sure that you really would want to hide the fact that it is a smart pointer from the view of the reader with auto.
std::shared_pointer<Bar> foo = getSharedPointer();
// use foo.get()
You may want to hide the exact type of managed object:
std::shared_pointer<auto> foo = getSharedPointer();

Return by reference in C++ - Reference assignment vs value assignment

Suppose I have:
class SomeObject {
};
SomeObject& f() {
SomeObject *s = new SomeObject();
return *s;
}
// Variant 1
int main() {
SomeObject& s = f();
// Do something with s
}
// Variant 2
int main() {
SomeObject s = f();
// Do something with s
}
Is there any difference between the first variant and the second? any cases I would use one over the other?
Edit: One more question, what does s contain in both cases?
First, you never want to return a reference to an object which
was dynamically allocated in the function. This is a memory
leak waiting to happen.
Beyond that, it depends on the semantics of the object, and what
you are doing. Using the reference (variant 1) allows
modification of the object it refers to, so that some other
function will see the modified value. Declaring a value
(variant 2) means that you have your own local copy, and any
modifications, etc. will be to it, and not to the object
referred to in the function return.
Typically, if a function returns a reference to a non-const,
it's because it expects the value to be modified; a typical
example would be something like std::vector<>::operator[],
where an expression like:
v[i] = 42;
is expected to modify the element in the vector. If this is
not the case, then the function should return a value, not
a reference (and you should almost never use such a function to
initialize a local reference). And of course, this only makes
sense if you return a reference to something that is accessible
elsewhere; either a global variable or (far more likely) data
owned by the class of which the function is a member.
In the first variant you attach a reference directly to a dynamically allocated object. This is a rather unorthodox way to own dynamic memory (a pointer would be better suited for that purpose), but still it gives you the opportunity to properly deallocate that object. I.e. at the end of your first main you can do
delete &s;
In the second variant you lose the reference, i.e. you lose the only link to that dynamically allocated object. The object becomes a memory leak.
Again, owning a dynamically allocated object through a reference does not strike me as a good practice. It is usually better to use a pointer or a smart pointer for that purpose. For that reason, both of your variants are flawed, even though the first one is formally redeemable.
Variant 1 will copy the address of the object and will be fast
Variant 2 will copy the whole object and will be slow (as already pointed out in Variant2 you cant delete the object which you created by calling new)
for the edit: Both f contain the same Object
None of the two options you asked about is very good. In this particular case you should use shared_ptr or unique_ptr, or auto_ptr if you use older C++ compilers, and change the function so it returns pointer, not reference. Another good option is returning the object by value, especially if the object is small and cheap to construct.
Modification to return the object by value:
SomeObject f() { return SomeObject(); }
SomeObject s(f());
Simple, clean, safe - no memory leaking here.
Using unique_ptr:
SomeObject* f() { return new SomeObject(); }
unique_ptr<SomeObject> s(f());
One of the advantages of using a unique_ptr or shared_ptr here is that you can change your function f at some point to return objects of a class derived from SomeObject and none of your client code will need to be changed - just make sure the base class (SomeObject) has a virtual constructor.
Why the options you were considering are not very good:
Variant 1:
SomeObject& s = f();
How are you going to destroy the object? You will need address of the object to call it's destructor anyway, so at some point you would need to dereference the object that s refers to (&s)
Variant 2. You have a leak here and not a chance to call destructor of the object returned from your function.

Returning value of auto_ptr in function

I encountered such code.
MyClass MyClass::get_information (const some_datastructure *record)
{
auto_ptr<MyClass > variable (new MyClass ());
variable ->set_article_id(record->article_id);
return *variable.get();
}
I understand this returns a (copy?) of object of type MyClass.
Initially, I thought it was returning auto_ptr object which didn't make sense to me (?)
since I thought auto_ptr object get destroyed when it goes out of scope.
Anyway, is the above code Ok? Does object *variable.get() exist when/after the function returns?
since it is returned by value, yes, the object is fine, although I don't understand the use of pointer or heap allocation for the matter...
Would be simpler with a regular variable:
MyClass var;
var.set_article_id(record->article_id);
return var;
Yes it does
Actually it creates a temporary rvalue of the underlying object of the pointer, in fact a copy. Notice that the return type is not MyClass* but MyClass. Thats why a copy is returned. *variable.get() also yields a rvalue.

Does destroying and recreating an object make all pointers to this object invalid?

This is a follow-up to this question. Suppose I have this code:
class Class {
public virtual method()
{
this->~Class();
new( this ) Class();
}
};
Class* object = new Class();
object->method();
delete object;
which is a simplified version of what this answer suggests.
Now once a destructor is invoked from within method() the object lifetime ends and the pointer variable object in the calling code becomes invalid. Then the new object gets created at the same location.
Does this make the pointer to the object in the calling valid again?
This is explicitly approved in 3.8:7:
3.8 Object lifetime [basic.life]
7 - If, after the lifetime of an object has ended [...], a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object [...] can be used to manipulate the new object, if: (various requirements which are satisfied in this case)
The example given is:
struct C {
int i;
void f();
const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
Strictly, this is fine. However, without extreme care, it will become a hideous piece of UB. For example, any derived classes calling this method won't get the right type re-constructed- or what happens if Class() throws an exception. Furthermore, this doesn't really accomplish anything.
It's not strictly UB, but is a giant pile of crap and fail and should be burned on sight.
The object pointer doesn't become invalid at any time (assuming your destructor doesn't call delete this). Your object was never deallocated, it has only called it's destructor, i.e. it has cleaned up its internal state (with regard to implementation, please note that standard strictly defines that the object is destroyed after destructor call). As you have used placement new to instantiate the new object at the exactly same address, it is technically ok.
This exact scenario is covered by section 3.8.7 of C++ standard:
If, after the lifetime of an object has ended and before the storage
which the object occupied is reused or released, a new object is
created at the storage location which the original object occupied, a
pointer that pointed to the original object, a reference that referred
to the original object, or the name of the original object will
automatically refer to the new object and, once the lifetime of the
new object has started, can be used to manipulate the new object [...]
That said, this is interesting only as learning code, as production code, this is horrible :)
The pointer only knows its address and as soon as you can confirm that the address of the new object is the one the pointer is pointing to, the answer is yes.
There are some cases where people would believe the address does not change, but in some cases it does change, e.g. when using C's realloc(). But that's another story.
You may want to reconsider explicitly calling the destructor. If there's code you want executed that happens to be in the destructor, move that code to a new method and call that method from the destructor to preserve the current functionality. The destructor is really meant to be used for objects going out of scope.
Creating a new object at the location of a destroyed one does not make any pointers valid again. They may point to a valid new object, but not the object you were originally referencing.
You should guarantee that all references were removed or somehow marked as invalid before destroying the original object.
This would be a particularly difficult situation to debug.