move語義這種「頂層設計」為什麼實現在std裡面

時間 2021-06-02 10:28:49

1樓:

因為並沒有「移動語義」這個東西,C++ 標準裡沒定義就直接使用了 move semantics,壓根就不覺得這是個專用術語,「移動語義」僅僅是個普通偏正短語,等於說「語義上要表達『這個東西被移動了』」。

std::move 是個庫函式,並不是 move semantics 裡的 move。標準裡 move 函式的部分甚至都沒提 move semantics。

這也是為什麼後者可以翻譯成「移動語義」而沒人叫前者「移動函式」。你還可以在中間加個襯字——「移動的語義」。

所以說移動語義不是靠哪個右值引用、輔助函式、cast、移動建構函式來實現的,非要說的話,是使用右值引用初始化某個物件的過程體現了移動語義。

完整起見,說兩句偏題的,move 函式底層是 static_cast, 寫成函式的作用不外乎輔助推導轉型的目標型別,但由於是函式,move 防止了純右值被移動,更有「移動」內味兒。

structA;

A&&a1=

A{};

// intended usageA&&

a2=static_cast

(A

{});

// weird but same as preview lineA&&

a3=move(A

{});

// dangling reference

給A寫乙個析構函式就會發現 a3引用的物件在 A&& a3 =move(A{});之後就析構掉了。

2樓:裴浩

因為 std::move 只是將變數型別轉換成右值引用型別,並不是執行了什麼實際的移動操作,比如觸發移動拷貝函式。它只是間接地觸發移動拷貝函式和移動拷貝賦值。

任何帶有名字的變數,都不是右值,而是左值。因此必須用 std::move 轉換成右值引用。

比如:#include

using

namespace

std;

struct

FooFoo

(const

Foo&

)Foo

(Foo&&)

noexcept

};voidf(

const

Foo&

foo)

// 過載 1

voidf(

Foo&&

foo)

// 過載 2

intmain

(int

argc

,char

*argv

)列印結果:

Foo ctor

f1f2

foo 是個左值,你傳入 foo 到 f 會優先匹配到接受左值引用的 f1。只有呼叫 std::move(foo) 將其轉換成右值引用,才能匹配到 f2。

從列印結果也可以看出,並沒有執行移動建構函式。把這裡的 std::move(foo) 改成 (Foo&&)foo 也是一樣的。

傳入過載 2 是為了表明,右值引用的物件(不管是左值還是右值)在之後就是不可用了,意思是狀態有可能和之前的不一樣了,再去使用就可能出現意想不到的結果。比如:

#include

using

namespace

std;

struct

Foo;

voidf(

const

Foo&

foo)

voidf(

Foo&&

foo)

intmain

(int

argc

,char

*argv

)看到這裡,你會想,那直接把過載 2 改成 void f(Foo& foo) 不也一樣?問題是, 這樣的話假如傳個右值,比如 f(Foo{}),那麼就會匹配到過載 1,也就不是最初想要的(修改右值的值再做處理)。

因此沒有右值引用的話,對於右值,必須先定義乙個變數(左值),將右值傳入來構造這個變數(拷貝構造),相當於多了一次不必要的拷貝:

FoogetFoo

()// getFoo() 返回了乙個臨時變數(右值),如果直接呼叫 f(getFoo()) 會匹配到 const Foo&,因此

// 這裡得顯式定義乙個左值,把臨時變數拷貝一遍(不必要的拷貝)

// 當然,實際上對 getFoo() 有可能發生返回值優化(RVO)來避免這次拷貝,但在 C++ 98/03 是沒有硬性規定的

Foofoo

(getFoo

());f(

foo);

右值引用的設計基本上就是為了解決這個問題,在此之前右值只能繫結到常引用,如果不能進行返回值優化,往往會多一次不必要的拷貝。

所謂的移動語義,其實只是通過增加了一種可以繫結到右值的引用型別(也就是右值引用),結合新的過載決議來實現的。通過 std::move 顯式將某個值(無論左值還是右值)轉換成右值引用,來匹配到合適的函式,從而減少一次多餘的拷貝。

為什麼易拉罐這種不甚合理的設計會如此流行?

古月懿軒 塑料瓶開蓋衛生,觸感也好,易拉罐先不談蓋子上的灰塵開啟後會直接會泡在飲料裡,邊緣縫隙裡的汙垢也很難處理,直接貼著嘴唇也很不適。塑料瓶摔不壞易拉罐摔到地上乙個坑估計都沒人願意拿去喝了雖然根本沒有被汙染。塑料瓶開蓋如果發現飲料要湧出可以立刻擰上待會再開啟但易拉罐只能看著泡沫淹沒自己的手或者桌子...

為什麼耐力型車架越來越多流行這種設計?

已重置 這樣錯開的確會導致座管受到的應力增加,但是這樣的確在外形上有別於老款車架,並且在有限範圍內合理的像你展示了車身材料的強度。 西紅柿大師 這有什麼好奇怪的,在蘋果出來前各種各樣外形的手機百花齊放,現在手機都是乙個樣子。這樣焊接還能省20克鋁合金,一年賣個20萬輛車,絕對能省乙個特斯拉出來 充電...

建築的頂層溫度為什麼高,怎麼去精確的計算得熱?

Levin 不能認為輻射穿透屋面,現行的方法是給出屋頂表面的溫度計算得熱,這些都是有資料可查的。相當於輻射量折合成溫公升了。對於窗戶部分的得熱才會直接計算輻射量。 嶽意賀 頂層房間所受的熱輻射通常來自兩個方面,一方面是透過立面,一方面是透過屋頂面。而其下面幾層的房間基本只受來自立面方向的熱輻射。而且...