-1

Sorry for the generic title but I can only describe what's going on.

std::unique_ptr<int> qq() {
    int b = 11;
    std::unique_ptr<int> f(&b);

    return f;
}

int main() {
    std::unique_ptr<int> q = qq();
    int *p = q.release();

    *p = 11;

    std::cout << *p << "\n";

    std::cout << *p << "\n";

    return 0;
}

outputs

11
32767 // why not 11?

returning with return std::move(f) results in an output of

11
0 // why not 11?
  • 1
    Why do you write `std::unique_ptr q(&b);` at all? –  May 11 '17 at 02:02
  • 1
    Also, printing `*p` twice and getting different results when you've just assigned to `*p` seems odd; if it doesn't segfault, I'd expect consistent output. Are you sure you didn't print `*q` or `b`? – ShadowRanger May 11 '17 at 02:03
  • @ShadowRanger I edited the code. I forgot to include the function call –  May 11 '17 at 02:04
  • 1
    The second example code works for me. Are you sure that's the exact code that segfaults? – Weak to Enuma Elish May 11 '17 at 02:10
  • @JamesRoot Your'e right I'm going to delete that until I can reproduce –  May 11 '17 at 02:16

1 Answers1

5

You're passing around a pointer to stack memory that has become defunct (the stack frame associated with it has unwound, so the variables there are no longer defined/reserved). The function calls involved in output are rewriting it. unique_ptr isn't really relevant here, you'd get the same undefined behavior by using:

int* qq() {
    int b = 11;
    return &b;
}

and avoiding the unique_ptr rigmarole, though the simpler version is more likely to be noticed as invalid by the compiler. In both cases, accessing the memory pointed to (b's address) becomes invalid (undefined behavior) the moment the function returns, and in practice, the value of b is overwritten by the next function call (in this case, to the operator<< overload of std::cout).

unique_ptr is for dynamically allocated memory, you can't just pass it the address of a stack value and expect it to do anything useful.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • For the record, I see nothing wrong with the second bit of example code; whatever the problem is, it's likely you've obscured it by omitting critical code, and it likely has nothing to do with `unique_ptr`, same as in the case I just explained; you've cloaked simple misuse of pointers in smart pointers, but the misuse of pointers is the problem, not smart pointers themselves. – ShadowRanger May 11 '17 at 02:13
  • You're right about the second example. Still looking into your answer –  May 11 '17 at 02:17
  • I used a simple raw pointer in the return and the compiler did indeed complain that the value escapes local scope. I'll look into how to properly return pointers from functions –  May 11 '17 at 02:32
  • 1
    @SephVelut: If the goal is just to dynamically allocate and return a `unique_ptr`, and you're on C++14 or higher, a simple `return std::make_unique(11);` would do the job (in C++14, it should be possible to basically never use `new` or `delete`, using only smart pointers as needed). Just keep it as a `unique_ptr`, don't `release` it (which removes the whole point of `unique_ptr`). – ShadowRanger May 11 '17 at 02:37