0

I have read this page about the move constructor. In that article, it use the template proxy to modify the temporary variable returned from function.

This is the implemention.

namespace detail {

    template <class T>
    struct proxy
    {
        T *resource_;
    };
} // detail

template <class T>
class MovableResource
{
private:
    T * resource_;

public:
    explicit MovableResource (T * r = 0) : resource_(r) { }
    ~MovableResource() throw() { delete resource_; }   // Assuming std:::auto_ptr like behavior.

    MovableResource (MovableResource &m) throw () // The "Move constructor" (note non-const parameter)
    : resource_ (m.resource_)
    {
        m.resource_ = 0; // Note that resource in the parameter is moved into *this.
    }

    MovableResource (detail::proxy<T> p) throw () // The proxy move constructor
    : resource_(p.resource_)
    {
        // Just copying resource pointer is sufficient. No need to NULL it like in the move constructor.
    }

    MovableResource & operator = (MovableResource &m) throw () // Move-assignment operator (note non-const parameter)
    {
        // copy and swap idiom. Must release the original resource in the destructor.
        MovableResource temp (m); // Resources will be moved here.
        temp.swap (*this);
        return *this;
    }

    MovableResource & operator = (detail::proxy<T> p) throw ()
    {
        // copy and swap idiom. Must release the original resource in the destructor.
        MovableResource temp (p);
        temp.swap(*this);
        return *this;
    }

    void swap (MovableResource &m) throw ()
    {
        std::swap (this->resource_, m.resource_);
    }

    operator detail::proxy<T> () throw () // A helper conversion function. Note that it is non-const
    {
        detail::proxy<T> p;
        p.resource_ = this->resource_;
        this->resource_ = 0;     // Resource moved to the temporary proxy object.
        return p;
    }
};

What about just add a constructor taking a const reference and use const_cast to change the variable to implement the move semantics like this.

MovableResource(const MovableResource& m)
{
    MovableResource& afterM = const_cast<MovableResource&>(m);
    afterM.swap(*this);
}

Does this introduce undefined behavior?

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
xsj0jsx
  • 149
  • 3
  • 9
  • 4
    Your "move" constructor is actually a *copy* constructor, using it for "movement" changes the semantics. And there is often a reason that objects are marked as constant, casting it away may indeed lead to [*undefined behavior*](http://en.wikipedia.org/wiki/Undefined_behavior). – Some programmer dude Aug 01 '14 at 02:00
  • In the old c++ standard, We need copy constructor like this to implement the move constructor, right? And I want to know does this will lead to undefined behavior. Yes? or no? – xsj0jsx Aug 01 '14 at 02:06
  • @xsj0jsx Implementing copy constructor using swap would be wrong in any C++ standard. – Soren Aug 01 '14 at 02:12
  • But we are implementing a class like `std::auto_ptr`, which have move semantics in its copy constructor – xsj0jsx Aug 01 '14 at 02:15
  • A class like your needs to be *very* well documented, because it changes the semantics and expectations of the copy-constructor. The big problem is your wish to cast away the const-ness of an object, and modify it. Technically it's *always* UB to modify a constant object, but you might get away with it *sometimes*, and it will be unpredictable when it will fail. – Some programmer dude Aug 01 '14 at 02:16

2 Answers2

1

Implementing move semantics under the hood of a copy constructor interface is just asking for trouble. By using const_cast you are effectively fooling clients of your interface into believing that your constructor will leave m unmodified when it ends up clobbering its value. Consider the following code:

const MovableResource first(/* Some resource 'A' */);
MovableResource second(first);
// 'first', supposedly 'const' now has potentially a different value!
Srikanth
  • 973
  • 2
  • 9
  • 19
  • Yes, you're right. I was just thinking how to solve the problem like this:`MovableResource func(); MovableResource a(func());` – xsj0jsx Aug 01 '14 at 02:23
0

MovableResource (MovableResource &m) throw () // The "Move constructor" (note non-const parameter)

That is not a move constructor, that is a copy constructor. A proper move constructor takes an rvalue reference as input:

MovableResource (MovableResource &&m) throw ()

MovableResource & operator = (MovableResource &m) throw () // Move-assignment operator (note non-const parameter)

Likewise, that is a copy assignment operator. A proper move assignment operator takes an rvalue reference as input:

MovableResource & operator = (MovableResource &&m) throw ()
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • What i want is to transfer the ownership of a resource held by an object to another object in C++03. Your code can only be implemented in c++11, right? – xsj0jsx Aug 01 '14 at 02:30
  • @xsj0jsx: Have a look at [Boost.Move](http://www.boost.org/doc/libs/1_55_0/doc/html/move.html), it provides C++11 style move semantics in C++03. – Mankarse Aug 01 '14 at 03:06