多次std::move同一std::unique_ptr未崩溃,代码是否合法?
Great question! Let's break this down step by step to understand what's happening here, and whether your code is actually valid C++.
First, the key rule about moved-from std::unique_ptr
The C++ standard clearly states that after a std::unique_ptr is moved from, it's left in a valid but unspecified state. To translate that into plain terms:
- It's still a legitimate, safe-to-manipulate object (you can destroy it, assign a new value to it, or even move from it again).
- You cannot make any assumptions about its internal value—it might be null, it might still hold the original pointer, or it could be something else entirely. The standard doesn't lock in a specific state here.
What happens in your first fun(std::move(p)) call?
Let's walk through this line by line:
- When you call
fun(std::move(p)), the ownership of the pointer stored in your localpis transferred to the function's parameterp(the one insidefun). - Your
funfunction does whatever it needs to with the pointer, then returns it. - Since you don't capture the return value, the returned
std::unique_ptris immediately destroyed. This means it releases the memory holding yourXobject (the one created withstd::make_unique). - The original
p(insomeFunction) is now stuck in that valid-but-unspecified state we talked about.
Is the second fun(std::move(p)) call legal?
The act of calling std::move on the moved-from p is technically allowed—because the object is still valid, and moving from it is a permitted operation. But what happens next is where things get risky:
- If your compiler/standard library implementation set
pto null after the first move (most modern ones do this), thenfunreceives a null pointer. Iffundoesn't dereference the pointer (e.g., it just returns it without accessing theXobject), nothing bad happens. - If your implementation didn't set
pto null (some older or non-conforming implementations might skip this), thenpstill holds the address of the already-deletedXobject. This makes the pointer passed tofuna dangling pointer. Iffundoesn't dereference it, you might get lucky and avoid a crash—but this is still undefined behavior (the C++ standard gives no guarantees about what happens here).
Why does your code run without crashing?
Your fun function probably doesn't perform any operations that dereference the pointer. Whether it gets a null pointer or a dangling one, simply passing it around and returning it won't trigger a crash. But this is pure luck—undefined behavior means the code could crash tomorrow, produce garbage results, or work fine depending on the compiler, optimization level, or even random chance.
The correct approach
If you intend to reuse p after calling fun, you need to capture the return value and reassign it to p:
p = fun(std::move(p));
This way, p regains ownership of the pointer (or whatever fun returns), and you're no longer relying on the unspecified state of a moved-from object. Alternatively, if you don't need p after the first call, you should avoid using it entirely to prevent accidental misuse.
内容的提问来源于stack exchange,提问作者softineer

