Babyburger
Babyburger

Reputation: 1828

Unique pointer still holds the object after moving

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:

Upvotes: 4

Views: 2282

Answers (3)

user2249683
user2249683

Reputation:

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)

Upvotes: 8

Galik
Galik

Reputation: 48635

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.

Upvotes: 8

cplusplusrat
cplusplusrat

Reputation: 1445

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.

Upvotes: 2

Related Questions