Why do some people use swap for move assignments?

后端 未结 4 701
一个人的身影
一个人的身影 2020-11-28 19:53

For example, stdlibc++ has the following:

unique_lock& operator=(unique_lock&& __u)
{
    if(_M_owns)
        unlock();
    unique_lock(std::move         


        
4条回答
  •  误落风尘
    2020-11-28 20:41

    I will answer the question from header: "Why do some people use swap for move assignments?".

    The primary reason to use swap is providing noexcept move assignment.

    From Howard Hinnant's comment:

    In general a move assignment operator should:
    1. Destroy visible resources (though maybe save implementation detail resources).

    But in general destroy/release function can fail and throw exception!

    Here is an example:

    class unix_fd
    {
        int fd;
    public:
        explicit unix_fd(int f = -1) : fd(f) {}
        ~unix_fd()
        {
            if(fd == -1) return;
            if(::close(fd)) /* !!! call is failed! But we can't throw from destructor so just silently ignore....*/;
        }
    
        void close() // Our release-function
        {
            if(::close(fd)) throw system_error_with_errno_code;
        }
    };
    

    Now let's compare two implementaions of move-assignment:

    // #1
    void unix_fd::operator=(unix_fd &&o) // Can't be noexcept
    {
        if(&o != this)
        {
            close(); // !!! Can throw here
            fd = o.fd;
            o.fd = -1;
        }
        return *this;
    }
    

    and

    // #2
    void unix_fd::operator=(unix_fd &&o) noexcept
    {
        std::swap(fd, o.fd);
        return *this;
    }
    

    #2 is perfectly noexcept!

    Yes, close() call can be "delayed" in case #2. But! If we want strict error checking we must use explicit close() call, not destructor. Destructor releases resource only in "emergency" situations, where exeption can't be thrown anyway.

    P.S. See also discussion here in comments

提交回复
热议问题