考慮以下 C 代碼
#include <iostream>
using namespace std;
struct WrapMe
{
WrapMe() { cout << "WrapMe Default Ctor of: " << this << endl; }
WrapMe(const WrapMe& other) { cout << "WrapMe Copy Ctor of " << this << " from " << &other << endl; }
WrapMe(WrapMe&& other) noexcept { cout << "WrapMe Move Ctor of " << this << " from " << &other << endl; }
~WrapMe() { cout << "Wrap Me Dtor of" << this << endl; }
};
struct Wrapper1
{
WrapMe& data()& { return member; }
WrapMe data()&& { return std::move(member); }
WrapMe member;
};
struct Wrapper2
{
WrapMe& data()& { return member; }
WrapMe&& data()&& { return std::move(member); }
WrapMe member;
};
int main()
{
auto wrapMe1 = Wrapper1().data();
auto wrapMe2 = Wrapper2().data();
}
與輸出
WrapMe Default Ctor of: 00000092E7F2F8C4
WrapMe Move Ctor of 00000092E7F2F7C4 from 00000092E7F2F8C4
Wrap Me Dtor of00000092E7F2F8C4
WrapMe Default Ctor of: 00000092E7F2F8E4
WrapMe Move Ctor of 00000092E7F2F7E4 from 00000092E7F2F8E4
Wrap Me Dtor of00000092E7F2F8E4
[...]
從成員中移出的正確方法是WrapMe:like Wrapper1(return by value) 還是 like Wrapper2(return by rvalue-reference) 呢?或者,正如輸出所暗示的那樣,這兩種方式在這里是等價的?如果不是,為什么?
uj5u.com熱心網友回復:
WrapMe&& data()&& { return std::move(member); }
這實際上并沒有移動任何東西。它只是回傳一個對成員的右值參考。例如我可以做
auto&& wrapMe2 = Wrapper2().data();
現在wrapMe2將是一個懸空的參考或
auto w = wrapper2();
auto&& wrapMe2 = std::move(x).data();
w現在我有一個沒有改變的成員的參考w。
只是因為WrapMe呼叫了移動建構式來初始化wrapMe2原行中的物件,才真正發生了移動操作。
版本
WrapMe data()&& { return std::move(member); }
已經呼叫移動建構式來構造回傳值。回傳的值永遠不會參考原始物件或其成員。
線
auto wrapMe1 = Wrapper1().data();
然后再次呼叫移動建構式以wrapMe1從 的回傳值進行初始化.data()。然而,允許編譯器省略第二個移動建構式呼叫,而是wrapMe1直接從 return 陳述句中的運算式構造。這就是為什么您會看到相同的結果。
對于 C 17 或更高版本,這種省略甚至是強制性的。
我不知道你的用例,所以我不能確定正確的方法是什么,但只是猜測你想要做什么:
為了兩個多載之間的一致性,我會使用回傳參考的版本。為左值而不是右data值提供對成員的可修改訪問會令人困惑。
但是,您實際上并不需要成員函式來執行此操作。通過data呼叫者無論如何都可以完全控制該成員,因此您可以public從一開始就創建該成員,然后可以直接以相同的方式使用它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/425968.html
上一篇:臨時物件中的字串文字?
