繁体   English   中英

在函数调用中访问并移动unique_ptr

[英]access and move unique_ptr in a function call

我有一个类似于以下的部分。

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

从理论上讲,它应该有效。 但由于编译器(vs2015)并未严格遵循标准,因此func(ptr->some_data), std::move(ptr)的顺序未定义,即ptr可能在访问之前被移动。

所以我的问题是如何使这个细分市场按预期工作?

完整代码如下:

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

你可以使用构造函数链来修复它:

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

原因:正如我在其他答案中所解释的那样,对func的调用肯定发生在委托构造函数调用之前,而实际移动unique_ptr (而不仅仅是更改其值类别)肯定发生在内部。

当然,这依赖于另一个C ++ 11功能,Visual C ++可能会或可能没有正确使用。 令人高兴的是, 自VS2013以来委托构造函数被列为支持


更好的做法是始终通过引用接受std::unique_ptr参数,如果您打算从它们中窃取,则通过右值引用接受 (如果您不会窃取内容,为什么要关心调用者具有哪种类型的智能指针?只需接受原始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> 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) } {}
};

你不会在第一时间遇到问题,并且调用者要求完全不变(必须提供rvalue,因为unique_ptr无论如何都是不可复制的)


使其成为通用规则的基本原理如下:按值传递允许复制或移动,无论哪个在呼叫站点更优化。 但是std::unique_ptr是不可复制的,所以实际的参数必须是rvalue。

该命令确实是未定义的,但这并不重要,因为std::move实际上并没有从指针移动,它只更改了值类别。

func(ptr->some_data)的调用 在指针移动之前进行,因为第一个是参数求值,后者发生在基本构造函数中,并且参数求值总是在函数调用之前排序。

如果它让你感觉更好,你可以把它写成100%的等价物:

 
 
 
  
  derive(unique_ptr<X> ptr): base{func(ptr->some_data), (unique_ptr<X>&&)ptr}{}
 
  

编辑:如果参数是按值传递,则实际移动不会在被调用函数内发生。 但是谁用unique_ptr做了这样的事情?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM