簡體   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