Does it make sense to reuse destructor logic by using std::swap in a move assignment operator?

非 Y 不嫁゛ 提交于 2019-12-04 04:55:16

问题


Consider the following:

class Example : boost::noncopyable
{
    HANDLE hExample;
public:
    Example()
    {
        hExample = InitializeHandle();
    }
    ~Example()
    {
        if (hExample == INVALID_HANDLE_VALUE)
        {
            return;
        }
        FreeHandle(hExample);
    }
    Example(Example && other)
        : hExample(other.hExample)
    {
        other.hExample = INVALID_HANDLE_VALUE;
    }
    Example& operator=(Example &&other)
    {
        std::swap(hExample, other.hExample); //?
        return *this;
    }
};

My thinking here is that the destructor will be running on "other" shortly, and as such I don't have to implement my destructor logic again in the move assignment operator by using swap. But I'm not sure that's a reasonable assumption. Would this be "okay"?


回答1:


It should be ok, but it's scarcely any better than the recommended technique of pass-by-value, in which case the move constructor would be used in this situation.




回答2:


Imagine the following:

// global variables
Example foo;

struct bar {
    void f() {
        x = std::move(foo); // the old x will now live forever
    }
    Example x;
}

A similar idiom, copy-and-swap (or in this case, move-and-swap), ensures that the destructor is run immediately, which I believe is a better semantic.

Example& operator=(Example other) // other will be moved here
{
    std::swap(hExample, other.hExample);
    return *this;
} // and destroyed here, after swapping



回答3:


My thinking here is that the destructor will be running on "other" shortly

Then your thinking is flawed. You can move from any object you have non-const access to. And the object can continue to live indefinitely after this.

It is technically correct to put your current data in the old object. But it's not a good idea. It's better to use a stack variable:

Example& operator=(Example &&other)
{
    Example temp(std::move(other));  //other is now empty.
    std::swap(hExample, temp);       //our stuff is in `temp`, and will be destroyed
    return *thisl
}

Or better yet (if you're not using Visual Studio) store your stuff in a wrapper that supports movement correctly, and let the compiler-generated move constructor do the job for you.



来源:https://stackoverflow.com/questions/9746748/does-it-make-sense-to-reuse-destructor-logic-by-using-stdswap-in-a-move-assign

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!