If the ownership is moved from one unique pointer into another, why can I call the method of that object, from which the ownership was transferred? In the example: why can I call the foo
method of p1
pointer? Isn't this an undefined behavior?
#include <iostream>
#include <memory>
class Car {
public:
int data{42};
void foo() {
std::cout << "Foo method is called." << std::endl;
}
~Car() {
std::cout << "Destructor is called." << std::endl;
}
};
int main() {
std::unique_ptr<Car> p1(new Car());
std::unique_ptr<Car> p2 = std::move(p1);
p1->foo(); // I can call this method, but isn't this an undefined behavior?
std::cout << p1->data << std::endl; // this give me segmentation error.
return 0;
}
Console Output:
Foo method is called.
Process finished with exit code -1073741819 (0xC0000005)
CodePudding user response:
You can make that call because it's valid syntax. That doesn't mean it isn't also undefined behavior.
Take a look at the unique_ptr
move constructor (the 5th one on that page). It says:
stores the null pointer in u
This means, in your example, after the move, p1
stores a null pointer. So, dereferencing it in any way is like dereferencing a null pointer, which is undefined behavior.
Undefined behavior doesn't mean the program will crash: in the case of p1->foo();
, foo
does not use anything from the object and might as well be a static or free function. It isn't accessing any memory that would cause a segmentation fault.
In other words, you crafted a situation where, by chance, a case of undefined behavior is the behavior you expect. This might not be true for someone else running the exact same code, or when running it on another platform, or compiled by another compiler, and so on.