The move function in emulation unique_ptr C ++ 03

I am trying to understand how C ++ 03 unique_ptr emulation is implemented. unique_ptr is very similar to std :: auto_ptr, but safer. It spits out compiler errors in cases where auto_ptr passed ownership implicitly (i.e. silently). For example, a simple appointment. The move function is the security key of emulated unique_ptr.

Questions:

  • Why are there three movement functions?
  • The third move function, which takes a link and turns it into an rvalue, is implemented (simplified) as follows.

     T move(T &t) { return T(detail_unique_ptr::rv<T>(t)); } 

In the above code, explicit conversion to T seems unnecessary. In fact, Visual Studio 2010 is completely happy without explicit conversion to T.

 T move(T &t) { return detail_unique_ptr::rv<T>(t); } 

g ++, clang, Comeau, however, do not like the second version. These compilers complain that there is no constructor for unique_ptr<T> that takes detail_unique_ptr::rv<T> as a parameter. Why is this? unique_ptr already defines a constructor (not explicit) that takes detail_unique_ptr::rv<T> as a parameter. Why does this not happen automatically?

+7
source share
1 answer

The reason is that you cannot initialize unique_ptr with another_ptr without doing a custom conversion (to rv, passing rvalue to the rv-accepting unique_ptr constructor). However, unless you explicitly call ctor unique_ptr (as in unique_ptr(...) ), you initialize the copy, which in your case first successfully creates the rvalue of the temporary unique_ptr, but then cannot copy this temporary value to the target of the return value, since user-defined transformations are not allowed in this copy (this is also known as the basic rule "there are no two user-defined transformations during initialization"). Msvc allows you to copy ctor usage using the nonconst unique_ptr link, which is non-standard.

When initializing an instance of a class from an object of the same class, there is no such two-stage initialization. The source object is simply passed to the implicit unique_ptr constructors, which converts it to rv using the rv accept constructor and thereby successfully constructs the target object of the return value.

For the same reason, there is no implicit conversion from unique_ptr<Derived> to unique_ptr<Base> . In the first step, unique_ptr<Base> will be created successfully, but then when copying this temporary object to the unique_ptr<Base> target, a restriction that cannot be used for certain transformations prevents success.

+3
source

All Articles