Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm sure some C++ lawyer can correct me, but isn't branching off of `m_ptr` (e.g. `CHECK()`ing the value) after `std::move(m_ptr)` technically Unspecified Behavior since `std::move(m_ptr)` leaves `m_ptr` as an Unspecified Value? It would be up to the compiler to define the behavior if they so pleased, but the C++ spec would not require such behavior to be defined at all.


There is a big difference between "undefined" and "unspecified" behavior. In this case, the behavior of `unique_ptr(unique_ptr&&)` is in fact specified. [0]

However, the bigger issue with that code is that it can easily stop working with a simple refactor. Consider:

    void foo(std::unique_ptr<int> ptr) {}
    void bar(std::unique_ptr<int>&& ptr) {}

    int main()
    {
        std::unique_ptr<int> p1{new int{1}};
        std::unique_ptr<int> p2{new int{2}};

        foo(std::move(p1));
        assert(p1 == nullptr);

        bar(std::move(p2));
        assert(p2 != nullptr);
     }
Neither of the above asserts will fire, but from the calling site, they look exactly the same. In my opinion, the more explicit option would be to do something like `bar(std::exchange(p2, nullptr))`

[0]: overload (5) https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_p...


Right, but changes in some other code potentially silently breaking assumptions at the calling site is exactly why you would want an assert like this in the first place.


Moves in C++ don't make the whole object invalid, it just leaves them in a valid but unspecified state, so that at least the destructor can still run.

This means calling operator bool on your unique_ptr ought to be fine, because the unique_ptr still has a valid state (you don't know what that state is, it's unspecified, but it's guaranteed to not be radioactive on mere contact. It has to be a valid unspecified state.)


Moves in C++ are a function call that can do whatever any other function call can. The type itself can have additional guarantees and the standard library types generally do. In the case of std::unique_ptr the guarantee is explicit that the moved-from unique_ptr is nulled.


I was wondering if anybody was going to point that out. It did occur to me that the CHECK was not technically valid due to that exact concern, but given that we control the compiler and the C++ library implementation and given that it's just debugging code (albeit debugging code that we ship to users) I'm fine with it.

In other words, I guess you shouldn't oughta do that generally, but I was fine with it being used there, and it did its job.


It appears that the question of what is valid on a moved-from object is tricky. Here is one discussion: https://stackoverflow.com/questions/7027523/what-can-i-do-wi... FWIW, here is the move operator for the type of the object in question: https://source.chromium.org/chromium/chromium/src/+/main:bas...


Note that the linked discussion is about the standard library. For your own types you can make whatever guarantees you want - ultimately as far as the language is concerned, moves are a function call like any other.


It’s an unspecified but required to be valid value for the moved type. The author mentions it’s a smart pointer type, which could easily be defined to act like this.


It appears that you need to be really smart in order to not blow your own foot off with this "smart pointer." I'll stick to the regular dumb kind, thanks.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: