access and move unique_ptr in a function call
c++, unique-ptr
Solution
You can fix it using constructor chaining:
struct derive : base
{
private:
derive(const D& some_data, unique_ptr<X>&& ptr) : base{some_data, std::move(ptr)} {}
public:
derive(unique_ptr<X> ptr): derive(func(ptr->some_data), std::move(ptr)) {}
};
Reason: As explained in my other answer, the call to `func` definitely takes place before the delegated constructor call, while actually moving the `unique_ptr` (as opposed to merely changing its value category) definitely takes place inside.
Of course, this relies on another C++11 feature which Visual C++ may or may not have gotten right. Happily, delegating constructors are listed as supported since VS2013.
An even better thing to do is just always accept `std::unique_ptr` arguments by reference, and by rvalue reference if you plan to steal from them. (And if you won't steal the content, why do you care what type of smart pointer the caller has? Just accept a raw `T*`.)
If you used
struct base
{
virtual ~base() = 0 {}
protected:
base(std::unique_ptr<base>&& new_state) :
previous_state{ std::move(new_state) } {}
private:
std::unique_ptr<base> previous_state;
};
struct derive_base : base
{
int get_a() const noexcept {
return a;
}
protected:
derive_base(int const new_a, std::unique_ptr<base>&& new_state) :
base{ std::move(new_state) }, a{ new_a } {}
private:
int a;
};
struct final_state : derive_base
{
final_state(std::unique_ptr<base>&& new_state) :
derive_base{ dynamic_cast<derive_base&>(*new_state).get_a(), std::move(new_state) } {}
};
you wouldn't have had the problem in the first place, and the caller requirements are completely unchanged (an rvalue must be provided, since `unique_ptr` is uncopyable anyway)
The rationale for making this a universal rule is as follows: pass by value allows either copying or moving, whichever is more optimal at the call site. But `std::unique_ptr` is non-copyable, so the actual parameter MUST be an rvalue anyway.
Problem
I have a segment similar to the following. ``` struct derive : base{ derive(unique_ptr ptr): base{func(ptr->some_data), std::move(ptr)}{} }; ``` In theory, it should work. But since the compiler (vs2015) does not strictly follow the standard, the order of `func(ptr->some_data), std::move(ptr)` is undefined, i.e. `ptr` may be moved before accessed. So my problem is how to make this segment work as expected? Complete code like this: ``` #include <memory> struct base { virtual ~base() = 0 {} protected: base(std::unique_ptr<base> new_state) : previous_state{ std::move(new_state) } {} private: std::unique_ptr<base> previous_state; }; struct derive_base : base { int get_a() const noexcept { return a; } protected: derive_base(int const new_a, std::unique_ptr<base> new_state) : base{ std::move(new_state) }, a{ new_a } {} private: int a; }; struct final_state : derive_base { final_state(std::unique_ptr<base> new_state) : derive_base{ dynamic_cast<derive_base&>(*new_state).get_a(), std::move(new_state) } {} }; ```