This question already has answers here:
Taking the address of a temporary object
(7 answers)
Closed 7 years ago.
I have two code segments which I expected the same outcome:
First one:
SomeClass somefunc(...){
SomeClass newObj;
//some codes modify this object
return newObj;
}
int main(){
SomeClass *p;
p = &(somefuc(...));
}
Second one:
SomeClass *somefunc(...){
SomeClass newObj;
//some codes modify this object
return &newObj;
}
int main(){
SomeClass *p;
p = somefunc(...);
}
Why is it I got a "taking the address of a temporary object" error when I tried to build the first code segment, while the second code segment doesn't produce an error?
Before you even think about this, you need to learn the rules of temporary lifetime.
The broad case is that a temporary object is destroyed at the end of the full-expression creating it. The implication is that if
SomeClass *p;
p = &(somefunc(...));
were allowed to work, p would be a dangling pointer, targeting an object that no longer exists.
The big exception to the above rule is that when a reference with automatic lifetime is directly bound to the temporary object, the lifetime of the temporary is extended to be equal to the lifetime of the reference. Note that this does not cover const T& make_lvalue(const T& t) { return t; } because the reference isn't binding directly, nor class member references.
There are a few cases which are completely safe, in which the address of the temporary is only used immediately and not stored for later. e.g.
memcpy(buffer, &f(), sizeof(decltype(f())));
Of course, this results in the "address of a temporary" error you're encountered, but you can work around it via
memcpy(buffer, std::addressof(f()), sizeof(decltype(f())));
But do NOT store the resulting pointer.
The first snippet does rightfully not compile because, as the compiler said, you cannot take the address of a temporary object because it would be destroyed at the end of the expression (here: the assignment). Thus, saving its address would be meaningless.
The second snippet does compile, but is still incorrect although it might seem to work for the reasons stated here (at least if you try to access the object through the pointer).
The first example does not compile because somefunc returns a value, and you attempt to take the address of this temporary thing it returns. This would work:
Someclass* p;
Someclass val = somefunc (...);
p = &val;
The second example does not compile -- or shouldn't -- because somefunc is supposed to return a Someclass, but instead it returns a pointer to a Someclass. Make it return Someclass* and then it should compile -- but now you're returning a pointer to a local variable, which no longer exists after you leave the function. Best solution is the first example, as patched here.
Related
How does the object unique_ptr<A> behaves if it's passed anonymously (or to no variable at all). How is it possible to know whether the unique_ptr has reference (it's being set into named variable) from within the c'tor.
basically the example shows calling method get() method directly from returned value object.
class A
{
public:
A(int a):_a(a) {}
~A() { std::cout << "d'tor A " << _a << std::endl; }
int _a;
};
std::unique_ptr<A> f1()
{
auto p1 = std::make_unique<A>(1);
return p1;
}
A *f2()
{
A * x = std::make_unique<A>(2).get(); // d'tor called 2
std::cout << x->_a << std::endl; // this will print 2 although destructed.
return x;
}
A *f3()
{
return std::make_unique<A>(3).get(); // d'tor called 3
}
int main(int argc, const char * argv[]) {
auto a=f1();
auto b=f2();
auto c=f3();
return 0;
} // d'tor called 1
In the above code, I understand the timing of the d'tor A 1 call, since when exiting the block where the unique referrer (denoted by local variable a) is destroyed.
But I don't understand the other 2 flows (d'tor A 2 and d'tor A 3 that called on the line of the creation - see in example). does it means that reference count in those cases is 0 from the first place, or that it raises to 1 and reduced right after.
P.S
This case intrigued me although it doesn't relate to any real case, but to clarify a concept that I tackled by accident.
It happens because I converted java-script where it's costumed to create a member and use it without intermediate variable (for example a().b().c() instead of _a=a(); _b=_a.b(); _c=_b.c()) and I accidentally used this notation on my c++ code.
You're confusing the lifetime of the std::unique_ptr and the object that it manages, with the lifetime of the pointer that you can get using it's get method.
A std::unique_ptr is the only owner of a dynamically allocated object, when it's destructor is called, it will call a deleter helper function on the pointer it is holding (in case of std::make_unique, it will just call delete or delete[], whichever is appropriate in this case)
In 1st case, the type of variable a, is std::unique_ptr<A>, the std::unique_ptr lives on the stack, (you didn't have to call std::move thanks to copy-elision), and when the main function finishes, it's removed from the stack, destructor is called, and the object is deleted, which is the behavior we usually want when using std::unique_ptr.
Now, 2nd and 3rd case, are the same, the 2nd case just introduces a temporary variable, but it doesn't change anything.
A * x = std::make_unique<A>(2).get();
When called like that, you create a temporary std::unique_ptr<A>, and on that temporary, you call get method, that returns a copy of the pointer that's managed. The issue is that the temporary std::unique_ptr<A> is destroyed at the end of the line, and the pointer you have is dangling, it has been already deleted. Dereferencing it and using in anyway is undefined behavior, and anything can happen.
3rd case is the same, temporary std::unique_ptr, you're getting it's pointer, but the temporary is removed, so delete is called on the object it was managing, and we have a danging pointer.
Whenever you have a smart pointer, never call get on a temporary, 1st store the temporary in a local variable, so it doesn't go out of scope when you're still using the pointer it is managing.
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?
Obviously, I would rather use std::shared_ptr<T> or std::unique_ptr<T>, but I'm dealing with some legacy code from 98/03.
My situation is:
auto* SomeClass::ReturnPtr( void )
{
return this -> UniquePtrObject.get( );
};
What happens if I do:
SomeObject.ReturnPtr( ) -> SomeFunction( );
Does the temporary pointer get automatically deleted? Or am I actually causing a leak?
This makes me think of an expression like Rvalue pointer. Rvalue pointers don't make sense, do they?
With
auto* SomeClass::ReturnPtr()
{
return this->UniquePtrObject.get();
}
Your pointer is valid as long as UniquePtrObject is (or any reset is done on it).
So SomeObject.ReturnPtr()->SomeFunction() is valid.
But following will make dangling pointer:
auto* createDanglingPointer()
{
SomeClass SomeObject = MakeSomeClass();
return SomeObject.ReturnPtr();
}
as someObject's lifetime ends at end of the scope.
Temporary pointers are really dangerous. Whenever scope of data which it was pointing previously ends it will be freed so the pointer will become dangling and will try to access some random location for which program has no access. It may gives you wrong results, values or program may terminated with exception illegal access.
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.
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.