在函数调用中访问和移动unique_ptr [英] access and move unique_ptr in a function call

查看:92
本文介绍了在函数调用中访问和移动unique_ptr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似于以下的段。

  struct derived:base {
derived(unique_ptr ptr) :base {func(ptr-> some_data),std :: move(ptr)} {}
};

理论上,它应该工作。但由于编译器(vs2015)不严格遵循标准, func(ptr-> some_data),std :: move(ptr)的顺序是未定义的,ie ptr 可能在访问之前被移动。



所以我的问题是如何使这个段工作正常? p>

填写如下代码

  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&上一个
};

struct derived_base:base {
int get_a()const noexcept {
return a;
}
protected:
derived_base(int const new_a,std :: unique_ptr< base> new_state):
base {std :: move(new_state)},{new_a} {}
private:
int a;
};

struct final_state:deriv_base {
final_state(std :: unique_ptr< base> new_state):
deriv_base {dynamic_cast< deriv_base&>(* new_state).get_a std :: move(new_state)} {}
};


解决方案

您可以使用构造函数链>

  struct derived:base 
{
private:
derived(const D& some_data,unique_ptr< X> ;& ptr):base {some_data,std :: move(ptr)} {}
public:
derived(unique_ptr< X> ptr):derived(func(ptr-> some_data ),std :: move(ptr)){}
};原因:正如我在其他回答中解释的,调用 func

code>绝对发生在委托构造函数调用之前,而实际上移动 unique_ptr (而不是仅仅改变其值类别) >

当然,这依赖于另一个C ++ 11功能,Visual C ++可能或可能不会得到正确。很高兴,委托构造函数从VS2013开始支持






只是总是通过引用接受 std :: unique_ptr 参数,如果您计划从它们偷取,则通过rvalue引用接受。 (如果你不会窃取内容,为什么你关心调用者有什么类型的智能指针?只接受一个原始的 T * 。)



如果你使用

  struct base 
{
virtual〜 base()= 0 {}

protected:
base(std :: unique_ptr< base>&& new_state):
previous_state {std :: move(new_state) } {}
private:
std :: unique_ptr< base&上一个
};

struct derived_base:base
{
int get_a()const noexcept {
return a;
}
protected:
derived_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:deriv_base
{
final_state(std :: unique_ptr< base>&& new_state):
deriv_base {dynamic_cast< deriv_base&> * new_state).get_a(),std :: move(new_state)} {}
};

你不会遇到这个问题,调用者的要求完全不变必须提供右值,因为 unique_ptr 无法复制)






std :: unique_ptr
是不可复制的,所以实际的参数必须是一个右值。


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) } {}
};

解决方案

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.

这篇关于在函数调用中访问和移动unique_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆