如果我有一個類C
像這樣:移動構造函數的這個實現是否會拋棄移動語義?
class C {
std::string s;
public:
C(std::string& s) : s(s) {}
C(std::string&& s) : C(s) {}
};
上午我通過調用從string&&
構造的string&
構造扔掉移動語義?
如果我有一個類C
像這樣:移動構造函數的這個實現是否會拋棄移動語義?
class C {
std::string s;
public:
C(std::string& s) : s(s) {}
C(std::string&& s) : C(s) {}
};
上午我通過調用從string&&
構造的string&
構造扔掉移動語義?
是的,你拋出你的移動語義。我可以用最直接的方法來演示如何通過示例。這是我能想出來的最令人激動的事情,所以我希望明確發生了什麼事情。
考慮一下:
#include <iostream>
struct S
{
int x;
S() :x(1) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(const S& s) : x(s.x) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(S&& s) : x(std::move(s.x)) { ++x, s.x=0; std::cout << __PRETTY_FUNCTION__ << '\n';}
~S() { std::cout << __PRETTY_FUNCTION__ << ':' << x << '\n';}
};
class C {
S s;
public:
C(S& s) : s(s) { std::cout << __PRETTY_FUNCTION__ << '\n';}
C(S&& s) : C(s) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
~C() { std::cout << __PRETTY_FUNCTION__ << '\n';}
};
int main()
{
C c{S{}};
}
輸出
S::S()
S::S(const S &)
C::C(S &)
C::C(S &&)
S::~S():1
C::~C()
S::~S():1
注意的S
實例構造,既不通過移動它們的。被「移動」到預定目標的任何S
將具有0
打印爲x
。沒有。第一個S
是來自S{}
的最初臨時值;第二個是通過C(C&&)
初始值設定項列表調用C(C&)
所作的副本。當這段代碼完成後,當我們開始運行析構函數鏈時,存在兩個完全構造的S
。
現在看這一點,相同的代碼,但採用s
構件上移動的語義:
#include <iostream>
struct S
{
int x;
S() :x(1) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(const S& s) : x(s.x) { std::cout << __PRETTY_FUNCTION__ << '\n';}
S(S&& s) : x(std::move(s.x)) { ++x, s.x=0; std::cout << __PRETTY_FUNCTION__ << '\n';}
~S() { std::cout << __PRETTY_FUNCTION__ << ':' << x << '\n';}
};
class C {
S s;
public:
C(S& s) : s(s) { std::cout << __PRETTY_FUNCTION__ << '\n';}
C(S&& s) : s(std::move(s)) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
~C() { std::cout << __PRETTY_FUNCTION__ << '\n';}
};
int main()
{
C c{S{}};
}
輸出的S
S::S()
S::S(S &&)
C::C(S &&)
S::~S():0
C::~C()
S::~S():2
兩個實例仍然構造,但後者是通過移動建設,吮吸第一個這樣做。當我們開始銷燬所有這些東西時,只有一個S
實例仍然有效;另一個則通過撤離而死亡。
長話短說,如果你的目標正在移動,你就開始射擊。我希望這有幫助,但我完全願意拋它,如果它不。
對於那些對於__PRETTY_FUNCTION__是什麼感到困惑的人來說,就像我一樣,[這裏](https://gcc.gnu.org/onlinedocs/gcc/Function-Names。 HTML)是一些文檔。 – anthropomorphic
@anthropomorphic它是*令人難以置信的*有用的模板,順便說一句。 – WhozCraig
我覺得這非常難以遵循,但它是有益的,謝謝。 – anthropomorphic
當人們提到「完美轉發」時,這並不是什麼提及。這只是一個移動構造函數調用一個拷貝構造函數(這正是我所假設的你的意思)。這是完美轉發:
class Foo{
public:
template<typename TBar> Foo(TBar&& bar): m_str(std::forward<TBar>(bar)){}
private:
std::string m_str;
};
這到底是怎麼回事的是,因爲模板參數推導和引用摺疊的規則,TBAR & &是所謂的「通用參考」,這意味着它可能將其類型解析爲TBar
,TBar&
或TBar&&
(您也可以在組合中添加const
和volatile
)。 std::forward
就像它的名字所說的那樣,並且TBar解析到的任何東西(保留它的推導類型)都會轉發給字符串的構造函數。
這不是一個有效的動作,因爲,首先,這不是一個動作ctor,是一個完美的轉發控制器,可以直接繞過成員參數初始化您的成員。在這種情況下,編譯器爲Foo生成一個默認的移動ctor。你的答案與Foo移動語義無關 – Manu343726
@ Manu343726:... -1,真的嗎?作者改變了他的頭銜;它最初提到「完美轉發」而不是移動語義。因此,我的帖子關於完美轉發。 – Shokwav
如果作者更改了問題,請相應地更新您的答案。我不知道這個問題是編輯過的,我只看到了一個與移動語義無關的答案。再次,更新答案 – Manu343726
我不熟悉C++ 11,但在這種情況下,移動構造函數不是簡單的多餘的? – stakx
@stakx移動構造函數基本上只是更快的複製構造函數,但它們只在調用者願意銷燬正在移動的對象時才起作用。所以不,他們做不同的事情。 – anthropomorphic
C在這個代碼之外的默認規定中沒有移動或copy-ctor,所以我不確定你在說什麼。 – WhozCraig