Unique pointer still holds the object after moving - c++

I'm going through some tutorials on how smart pointers work in C++, but I'm stuck on the first one I tried: the unique pointer. I'm following guidelines from wikipedia, cppreference and cplusplus. I've also looked at this answer already. A unique pointer is supposed to be the only pointer that has ownership over a certain memory cell/block if I understood this correctly. This means that only the unique pointer (should) point to that cell and no other pointer. From wikipedia they use the following code as an example:
std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; //Compile error.
std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is rendered invalid.
p3.reset(); //Deletes the memory.
p1.reset(); //Does nothing.
Until the second line, that worked fine for me when I test it. However, after moving the first unique pointer to a second unique pointer, I find that both pointers have access to the same object. I thought the whole idea was for the first pointer to be rendered useless so to speak? I expected a null pointer or some undetermined result. The code I ran:
class Figure {
public:
Figure() {}
void three() {
cout << "three" << endl;
}
};
class SubFig : public Figure {
public:
void printA() {
cout << "printed a" << endl;
}
};
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t; // used to halt execution so I can verify everything works up til here
testing->three(); // why is this not throwing a runtime error?
}
Here, testing has been moved to testing2, so I'm surprised to find I can still call the method three() on testing.
Also, calling reset() doesn't seem to delete the memory like it said it would. When I modify the main method to become:
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t;
testing.reset(); // normally this should have no effect since the pointer should be invalid, but I added it anyway
testing2.reset();
testing2->three();
}
Here I expect three() not to work for testing2 since the example from wikipedia mentioned the memory should be deleted by resetting. I'm still printing out printed a as if everything is fine. That seems weird to me.
So can anyone explain to me why:
moving from one unique pointer to another unique pointer doesn't make the first one invalid?
resetting does not actually remove the memory? What's actually happening when reset() is called?

Essentially you invoke a member function through a null pointer:
int main()
{
SubFig* testing = nullptr;
testing->three();
}
... which is undefined behavior.
From 20.8.1 Class template unique_ptr (N4296)
4 Additionally, u can, upon request, transfer ownership to another
unique pointer u2. Upon completion of such a transfer, the following
postconditions hold:
u2.p is equal to the pre-transfer u.p,
u.p is equal to nullptr, and
if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
(emphasis mine)

After the std::move() the original pointer testing is set to nullptr.
The likely reason std::unique_ptr doesn't check for null access to throw a runtime error is that it would slow down every time you used the std::unique_ptr. By not having a runtime check the compiler is able to optimize the std::unique_ptr call away entirely, making it just as efficient as using a raw pointer.
The reason you didn't get a crash when calling the nullptr is likely because the function you called doesn't access the (non-existent) object's memory. But it is undefined behavior so anything could happen.

On calling std::unique_ptr<int> p3 = std::move(p1); your original pointer p1 is in undefined state, as such using it will result in undefined behavior. Simply stated, never ever do it.

Related

Why does this smart pointer give the correct result when its target should have been deleted?

Disclaimer: I know this is not how unique_ptr should be used, but for the sake of understanding, I would like to know what is going on here. Thank you!
Consider this function:
void foo(int* a) {
unique_ptr<int> pointer_in_function(a);
}
And this main function:
int main(void) {
int* myInt = new int(5);
unique_ptr<int> pointer_in_main(myInt);
foo(myInt);
cout << *pointer_in_main << endl;
cout << *pointer_in_main << endl;
cin.get();
return 0;
}
I consistently get the correct answer from the first cout. The second is undefined. The program sometimes crashes with a critical error on exit, but not always.
What I do not understand is why the first cout gives the correct answer consistently. Shouldn't the integer pointed to by myInt have been deleted when pointer_in_function went out of scope? Thank you for your help!
edit: As an aside, just to be sure, am I correct in my assumption that calling foo should delete my integer because pointer_in_function goes out of scope?
What I do not understand is why the first cout gives the correct answer consistently.
Most implementations do not clear memory after deleting or return it back to the OS, so if you inspect the memory quickly after deleting, the chances of it not having been overwritten yet are higher.
That's one of the valid consequences of undefined behaviour. It may be 100% predictable on your particular implementation, though it need not behave the same on others.
It's not a good way to do (pure enough) experiments with constructors / destructors or deletion. If you have an object uncorrupted it DOESN'T imply that a delete operator hasn't been called (as its effect to the memory data is undefined and indeed many memory manager implementations don't change the released memory content immediately). Instead, create a class with explicit constructor(s) and destructor reporting their invocation and use it in place of int. As a destructor call prepends an object deletion (and as your code doesn't use stack or static allocation of an object under test, a destructor call is always implies a deletion), you may use destructor calls to trace deletions. Something like:
#include <iostream>
class MyObj {
int value;
MyObj(int v) : value(v) {std::cerr << "MyObj ctor called"<<std::endl;}
~MyObj() {std::cerr << "MyObj dtor called"<<std::endl;}
};
.....
int main (int argc, char **argv) {
MyObj* myInt = new MyObj(5);
....
}

Nullptr and checking if a pointer points to a valid object

In a couple of my older code projects when I had never heard of smart pointers, whenever I needed to check whether the pointer still pointed to a valid object, I would always do something like this...
object * meh = new object;
if(meh)
meh->member;
Or when I needed to delete the object safely, something like this
if(meh)
{
delete meh;
meh = 0;
}
Well, now I have learned about the problems that can arise from using objects and pointers in boolean expressions both with literal numbers, the hard way :. And now I've also learned of the not so new but pretty cool feature of C++, the nullptr keyword. But now I'm curious.
I've already gone through and revised most of my code so that, for example, when deleting objects I now write
if(meh)
{
delete meh;
meh = nullptr;
}
Now I'm wondering about the boolean. When you pass just say an int into an if statement like this,
int meh;
if(meh)
Then it implicitly checks for zero without you needing to write it.
if(meh == 0) // does the exact same check
Now, will C++ do the same for pointers? If pass in a char * like this to an if statement?
char * meh;
if(meh)
Then will it implicitly compare it with nullptr? Because of how long I have been writing these ifs like this, it is second nature at this point to check if the pointers valid before using by typing if (object *) and then calling its members. If this is not the functionality why not? Too difficult to implement? Would solve some problems by removing yet another tiny way you could mess up your code.
In C, anything that's not 0 is true. So, you certainly can use:
if (ptrToObject)
ptrToObject->doSomething();
to safely dereference pointers.
C++11 changes the game a bit, nullptr_t is a type of which nullptr is an instance; the representation of nullptr_t is implementation specific. So a compiler may define nullptr_t however it wants. It need only make sure it can enforce proper restriction on the casting of a nullptr_t to different types--of which boolean is allowed--and make sure it can distinguish between a nullptr_t and 0.
So nullptr will be properly and implicitly cast to the boolean false so long as the compiler follows the C++11 language specification. And the above snippet still works.
If you delete a referenced object, nothing changes.
delete ptrToObject;
assert(ptrToObject);
ptrToObject = nullptr;
assert(!ptrToObject);
Because of how long I have been writing these ifs like this, it is second nature at this point to check if the pointers valid before using by typing if (object *) and then calling it's members.
No. Please maintain a proper graph of objects (preferably using unique/smart pointers). As pointed out, there's no way to determine if a pointer that is not nullptr points to a valid object or not. The onus is on you to maintain the lifecycle anyway.. this is why the pointer wrappers exist in the first place.
In fact, because the life-cycle of shared and weak pointers are well defined, they have syntactic sugar that lets you use them the way you want to use bare pointers, where valid pointers have a value and all others are nullptr:
Shared
#include <iostream>
#include <memory>
void report(std::shared_ptr<int> ptr)
{
if (ptr) {
std::cout << "*ptr=" << *ptr << "\n";
} else {
std::cout << "ptr is not a valid pointer.\n";
}
}
int main()
{
std::shared_ptr<int> ptr;
report(ptr);
ptr = std::make_shared<int>(7);
report(ptr);
}
Weak
#include <iostream>
#include <memory>
void observe(std::weak_ptr<int> weak)
{
if (auto observe = weak.lock()) {
std::cout << "\tobserve() able to lock weak_ptr<>, value=" << *observe << "\n";
} else {
std::cout << "\tobserve() unable to lock weak_ptr<>\n";
}
}
int main()
{
std::weak_ptr<int> weak;
std::cout << "weak_ptr<> not yet initialized\n";
observe(weak);
{
auto shared = std::make_shared<int>(42);
weak = shared;
std::cout << "weak_ptr<> initialized with shared_ptr.\n";
observe(weak);
}
std::cout << "shared_ptr<> has been destructed due to scope exit.\n";
observe(weak);
}
Now, will C++ do the same for pointers? If pass in a char * like this to an if statement?
So to answer the question: with bare pointers, no. With wrapped pointers, yes.
Wrap your pointers, folks.
It's not possible to test whether a pointer points to a valid object or not. If the pointer is not null but does not point to a valid object, then using the pointer causes undefined behaviour. To avoid this sort of error, the onus is on you to be careful with the lifetime of objects being pointed to; and the smart pointer classes help with this task.
If meh is a raw pointer then there is no difference whatsoever between if (meh) and if (meh != 0) and if (meh != nullptr). They all proceed iff the pointer is not null.
There is an implicit conversion from the literal 0 to nullptr .
It is always set a pointer to zero after invalidating it so that you know a pointer that's non-zero is valid" is an anti-pattern. What happens if you have two pointers to the same object? Setting one to zero won't be better and it does not affect the other.

"delete this" to an object that's allocated with std::shared_ptr?

I know that it's possible to say delete this in C++ whenever you allocated something with new, using traditional pointers. In fact, I also know that it's good practice IF you handle it carefully. Can I have an object say delete this if it's being held by an std::shared_ptr? And that ought to call the destructor, right? To give you an idea, I'm making a game where a ship can shoot missiles, and I'd like to have the missiles delete themselves.
No, it's not safe, the lifetime of the object is determined by holders of shared_ptr, so the object itself cannot decide whether it wants to die or not. If you do that, you'll get double
delete when last shared_ptr dies. The only solution I can offer is "rethink your design" (you probably don't need shared_ptr in the first place, and missiles probably could be values or pooled objects).
For a missile to delete itself it must own itself, or at the very least, share ownership of itself with others. Since you say that there is a shared_ptr to the missile, I am assuming that you already have multiple objects sharing ownership of the missile.
It is possible for the missile to hold a shared_ptr to itself, and thus share in the ownership of itself. However this will always create a cyclic ownership pattern: For as long as the missile's shared_ptr data member refers to itself, the reference count can never drop to zero, and thus the missile is leaked.
You could have an external object or event tell the missile to delete itself but then I'm not sure what the point is. In order to tell the missile to delete itself, that communication should take place via a shared_ptr, and then the delete isn't really going to happen until that shared_ptr lets go of the missile.
Yes, it is possible. No, I don't think it is a good idea. It looks prone to memory leakage to me and doesn't actually add value. But for the curious, here is how you would do it:
#include <iostream>
#include <memory>
class missile
: public std::enable_shared_from_this<missile>
{
std::shared_ptr<missile> self_;
public:
missile()
{}
~missile() {std::cout << "~missile()\n";}
void set_yourself()
{
self_ = shared_from_this();
}
void delete_yourself()
{
if (self_)
self_.reset();
}
};
int main()
{
try
{
std::shared_ptr<missile> m = std::make_shared<missile>();
m->set_yourself();
std::weak_ptr<missile> wp = m;
std::cout << "before first reset()\n";
m.reset();
std::cout << "after first reset()\n";
// missile leaked here
m = wp.lock();
m->delete_yourself();
std::cout << "before second reset()\n";
m.reset(); // missile deleted here
std::cout << "after second reset()\n";
}
catch (const std::exception& e)
{
std::cout << e.what() << '\n';
}
}
I know I'm late to the show but I ran into wanting to do this myself just now and realized that it is "kind-of-possible" but you need to take care of a few things.
Howard's answer is on the right track but misses the mark as you shouldn't leave construction of the original shared_ptr to the client. This is what opens up the risk of memory leaks. Instead you should encapsulate the construction and only allow weak pointers.
Here is an example:
class Missile{
private:
Missile(...){ }; // No external construction allowed
Missile(const Missile&) = delete; // Copying not allowed
void operator = (const Missile&) = delete; // -||-
std::shared_ptr<Missile> m_self;
public:
template<typename... Args>
static MissilePtr makeMissile(Args... args){
auto that = std::make_shared<Misile>(args...);
that.m_self = that; // that holds a reference to itself (ref count = 2)
return that; // 'that' is destroyed and ref-count reaches 1.
}
void die(){
m_self.reset();
}
...
};
typedef std::weak_ptr<Missile> MissilePtr;
void useMissile(MissilePtr ptr){
auto missile = ptr.lock(); // Now ptr cannot be deleted until missile goes out of scope
missile->die(); // m_self looses the reference but 'missile' still holds a reference
missile->whatever(); // Completely valid. Will not invoke UB
} // Exiting the scope will make the data in missile be deleted.
Calling die() will result in semantically the same effect as delete this with the added benefit that all MissilePtr that are referring to the deleted object will be expired. Also if any of the MissilePtr are used for accessing this then the deletion will be delayed until the temporary std::shared_ptr used for the access is destroyed saving you life-time headaches.
However you must make sure that you always keep at least one MissilePtr around and at some point call die() otherwise you will end up with a memory leak. Just like you would with a normal pointer.
This question is quite old, but I had a similar issue (in this case a "listener" object that had to manage its own lifecycle while still being able to share weak pointers), and googling around did not provide a solution for me, so I am sharing the solution I found, assuming that:
The object manages it's own lifecycle, and hence will never share a
share_ptr, but a weak_ptr (if you need shared_ptr's a similar
solution + use_shared_from_this could do it).
It is a bad idea to break RAII, and hence we will not do it: what we
adress here is the issue of having a shared_ptr owned by an object
itself, as containing a member share_ptr leads to double call to
the object destruction and normally a crash (or at least undefined
behaviour), as the destructor is called twice (once at normal
object destruction and a second one when destroying the self
contained shared_ptr member).
Code:
#include <memory>
#include <stdio.h>
using std::shared_ptr;
using std::weak_ptr;
class A {
struct D {
bool deleted = false;
void operator()(A *p) {
printf("[deleter (%s)]\n", p, deleted ? "ignored":"deleted");
if(!deleted) delete p;
}
};
public: shared_ptr<A> $ptr = shared_ptr<A>(this, D());
public: ~A() {
std::get_deleter<A::D>($ptr)->deleted = true;
}
public: weak_ptr<A> ptr() { return $ptr; }
};
void test() {
A a;
printf("count: %d\n", a.ptr().lock().use_count());
printf("count: %d\n", a.ptr().use_count());
}
int main(int argc, char *argv[]) {
puts("+++ main");
test();
puts("--- main");
}
Output:
$ g++ -std=c++11 -o test test.cpp && ./test
+++ main
count: 2
count: 1
[deleter (ignored)]
--- main
The shared_ptr deleter should never get called for an object allocated in stack, so when it does at normal object destruction, it just bypasses the delete (we got to this point because the default object destructor was already called).

Interesting issue when attempting to reset pointer

Being that my C++ isn't that great, this may be a really simple/obvious answer, but it sure has me stumped. Keep in mind its kinda late here and I'm a little tired. I got this code here:
void TestFunc(int *pVar)
{
cout << endl << *pVar << endl;
delete pVar;
pVar = nullptr;
}
int main(int argc, char *argv[])
{
int *z(new int);
*z = 5;
TestFunc(z);
if (z == nullptr)
cout << "z Successfully Deleted!" << endl;
else cout << "z NOT deleted!" << endl;
return 0;
}
The program compiles just fine with no errors or warning. When I run it, it displays 5, just as I'd expect. However, it says z NOT deleted!. I am curious as to why pVar is not getting set to nullptr even though I explicity set it in my TestFunc() function. Any help would be appreciated. If it matters, this is Visual Studio 2010 and just a regular unmanaged C++ application.
Because it's being passed by value (i.e. as a copy).
If you want the variable itself to be passed (rather than just its value, which is copied), use
void TestFunc(int *&pVar)
instead.
Note that delete only cares about the pointee, not the pointer. So "deleting" a copy of a pointer deletes the same thing as the original pointer, because in either case you're deleting their targets, which are the same.
TestFunc accepts the pointer by value, so setting it to null inside the function actually only affects the copy in the function and is not visible to the caller. So pVar is set to null, but z in main() is not because those are different variables.
To make the change visible to the caller pass the pointer by reference or via a double pointer.
It is late (sorry!!!).
z is passed by value. z is not pVar. You assigned the value of nullptr to pVar and not to z.
The "idiom" you present is generally advocated as Safe Delete.
It was already known in C (though it was a free back then): zero-out the pointer you just freed / deleted to avoid doing so twice.
The trouble is, you zero out the current pointer, but any copy of it still point to the same memory area, which now contains garbage.
Memory handling is a difficult topic, the fundamental concept is ownership. At any point in time, the owners of a particular memory zone should be well identified, and they should have the responsibility of returning it to the system when appropriate.
The first step in this direction is the use of smart pointers, for example std::unique_ptr or boost::scoped_ptr. For shared ownership (experts only), std::shared_ptr might come handy, but you're not there yet.
If you write a delete in your code, it means you are exposing yourself to leaks. It is not bad in itself, but it calls for careful review, and makes the code brittle (ie, likely to break on change). In your case:
int main() {
boost::scoped_ptr<int> i(new 5);
foo(*i);
} // memory returned to system by ~scoped_ptr()

Object creation differences

What is the difference between the 2 following methods to create an object?
Test* t = new Test();
and
Test* t;
Your answers to second sample match with what i thought it would do (no object is created) But
class Test {
public:
void bla(void) {
std::cout << "test" << std::endl;
};
};
int main(void) {
Test* test;
test->bla();
}
gives me the output "test"... So there is actually an Object
The first one does 4 things:
create pointer to Test
allocate memory and creates Test object (note, that it's Test, not test )
the new object is value initialized, because of the () - see Do the parentheses after the type name make a difference with new? for more information
initializes the pointer to point to the created object
The second one just creates pointer to Test. And it's not initialized.
#yogi - for your edit - this is totally Undefined Behavior, as the pointer is uninitialized. And no, it's not an object. See C++ function called without object initialization for more information.
The second one doesn't create any object at all and trying to access it will result in Bad Thingsā„¢.
This is a pointer, allocated on the stack, and uses 32 or 64 bits of memory.
Test * t;
This will create an object of type Test on the heap (an you need to desalocate it)
t = new Test();
This will create an object of type Test on the stack (no need to desalocate it. It will disapear as soon as you exit the current context)
Test t2;
Edit
Your example works because the compiler optimized you code : it notices that you don't use any member, so it could doesn't make the effort you look for the instance.
The first one is a method to create an instance of an object.
The second on is not a method to create an instance of an object. It merely declares a pointer, which remains uninitialised.
After your update: The reason that it still successfully calls bla() is just undefined behaviour. Because that's exactly what the C++ Standard defines what is happening when you work with unsafe memory (in this case some arbitrary address that your pointer is pointing to) - the behaviour is undefined.
As others already said, you're just lucky that the undefined behaviour that you trigger happens to look like what you thought you want (essentially because your Test::bla() is almost like a global free function). To see your example crash and burn, just add some non-trivial class members:
class Test {
public:
void bla(void) {
std::cout << "test: " << x << std::endl;
};
int x;
};
You can think of your original example as a free function
void bla(Test * p) { std::cout << "test" << std::endl; }
which you just happen to call with a garbage parameter, but since you don't use the parameter, nothing bad happens. In my modified example, we try to access p->x and die.
Test* test;
test->bla();
As other answers have stated, Test* test does not create any object. It is a uninitialized pointer to Test. It is not pointing to anything valid unless it is initialized to point to a valid Test object.
Dereferencing an Uninitialized pointer like you are results in a Undefined Behaior.
In your case it does not crash because you are not referring this inside bla().
Nevertheless its still undefined behavior to dereference unitialized test.
To reiterate the above point, the following example will mostly crash.
#include<iostream>
class Test
{
public:
int i;
void bla(void)
{
std::cout << "test" << std::endl;
std::cout << "test->i" << this->i <<std::endl;
}
};
int main(void)
{
Test* test;
test->bla();
return 0;
}