簡體   English   中英

C ++ std ::移動指針

[英]C++ std::move a pointer

我有一個提供給用戶的C ++框架,這些用戶應該使用我編寫的模板包裝器以及自己的實現作為模板類型。 包裝器充當RAII類,並且包含指向用戶類的實現的指針。 為了使用戶的代碼干凈整潔(我認為),我提供了一個強制轉換運算符,該運算符將包裝器轉換為其持有的指針。 這樣(連同其他一些重載),用戶可以使用我的包裝器,就像它是一個指針一樣(非常類似於shared_ptr)。

我遇到一個極端的情況,用戶調用一個函數,該函數在包裝器上使用std :: move指向其實現類的指針。 這是一個看起來像的例子:

#include <iostream>
using namespace std;

struct my_interface {
    virtual int bar() = 0;
};

template <typename T>
struct my_base : public my_interface {
    int bar() { return 4; }
};

struct my_impl : public my_base<int> {};

template <typename T>
struct my_wrapper {
    my_wrapper(T* t) {
        m_ptr = t;
    }

    operator T*() {
        return m_ptr;
    }

private:
    T* m_ptr;
};

void foo(my_interface* a) {
    std::cout << a->bar() << std::endl;
}


int main()
{
    my_impl* impl = new my_impl();
    my_wrapper<my_impl> wrapper(impl);
    foo(std::move(wrapper));
    //foo(wrapper);

    return 0;
}

[這當然只是一個例子,在包裝器中還有更多的方法,但是我很確定在這種情況下,這里沒有作用]

用戶,就像我期望的那樣,如果在包裝器上調用了std :: move,那么在對foo的調用之后,包裝器將為空(或者至少像被移動一樣被修改),但是實際上唯一的方法是在foo之前調用的是強制轉換運算符。

有沒有一種方法,使呼叫foo兩個電話之間區分到foo使用和不打電話時即std::move

編輯感謝Mooing Duck的評論,我發現了my_wrapper知道需要哪個調用的方法,但是我真的不確定這是最好的方法,並且也會對此發表評論:

代替以前的演員,使用以下兩個:

operator T*() & {
    return m_ptr;
}

operator T*() &&{
    //Do something
    return m_ptr;
}

現在,在使用std :: move進行調用時會調用operator T*() &&而在不使用std :: move進行調用時會調用operator T*() &

就像我希望的那樣,用戶希望如果在包裝器上調用了std :: move,那么在對foo的調用之后,包裝器將為空(或者至少像被移動一樣被修改)

您的期望是錯誤的。 僅當發生移動時(即,某種資源的所有權已轉移),才會對其進行修改。 但是調用foo不會做任何事情,因為它只能訪問包裝器中保存的指針。 調用std::move不會執行任何操作,只是將其參數強制轉換為右值,這不會改變它。 某些通過引用接受右值的函數可能會對其進行修改,因此std::move啟用了該值,但它本身並未這樣做。 如果您不將右值傳遞給此類函數,則不會進行任何修改。

如果您確實要使其為空,則可以添加一個重載來做到這一點:

template<typename T>
void foo(my_wrapper<T>&& w) {
    foo(static_cast<my_interface*>(w));
    w = my_wrapper<T>{};  // leave it empty
}

但為什么? 為什么要這樣做?

如果您這樣做,則包裝器不會為空:

my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2 = std::move(w);

並且不會因以下原因而留空:

my_wrapper<my_impl> w(new my_impl);
my_wrapper<my_impl> w2;
w2 = std::move(w);

如果復制右值包裝器不能將其保留為空,那么為什么只需要訪問其成員就可以將其保留為空? 這是沒有意義的。

即使你的包裝有一個移動構造函數和移動賦值操作符,這樣上面的例子離開w空,仍然並不意味着訪問一個右值對象的成員應該修改的對象。 為什么將operator T*轉換為左值或右值會產生邏輯上的差異?

(另外,你真的能肯定的是兼具, 從包裹指針類型的隱式轉換是一個好主意?提示:這不是一個好主意,一般更願意讓你轉換明確, 特別是如果你正在處理的指針。動態分配的對象。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM