如果構建并運行這個簡短的例子
#include <memory> // for class template `unique_ptr`
#define LOG() std::printf("[%p] %s\n", this, __PRETTY_FUNCTION__)
class bar_t final
{
public:
bar_t(int val) : m_val(val) { LOG(); }
~bar_t(void) { LOG(); }
bar_t(bar_t&& dying) : m_val(std::move(dying.m_val)) { LOG(); }
int get_value(void) const { return m_val; }
private:
int m_val;
};
class foo_t final
{
public:
foo_t(int a_val) : m_bar(a_val) { LOG(); }
~foo_t(void) { LOG(); }
bar_t m_bar;
};
std::unique_ptr<foo_t> gen_foo(int val)
{
return std::make_unique<foo_t>(val);
}
int main(int argc, char *argv[])
{
#if 1
bar_t&& bar = std::move(gen_foo(42)->m_bar); // Bad
// bar_t& bar = gen_foo(42)->m_bar; // gives same result as previous line
#else
bar_t bar(std::move(gen_foo(42)->m_bar)); // Good
#endif
std::printf("bar.get_value() = %d\n", bar.get_value());
return 0;
}
我們會有這個輸出
[0x5616d6510e70] bar_t::bar_t(int)
[0x5616d6510e70] foo_t::foo_t(int)
[0x5616d6510e70] foo_t::~foo_t()
[0x5616d6510e70] bar_t::~bar_t()
bar.get_value() = 0
wherebar.get_value()回傳 0 而不是 42。另一方面,如果我們將#if標準設定為 0,再次構建并運行,我們將擁有
[0x55acef3bfe70] bar_t::bar_t(int)
[0x55acef3bfe70] foo_t::foo_t(int)
[0x7fff70612574] bar_t::bar_t(bar_t&&)
[0x55acef3bfe70] foo_t::~foo_t()
[0x55acef3bfe70] bar_t::~bar_t()
bar.get_value() = 42
[0x7fff70612574] bar_t::~bar_t()
回傳bar.get_value()42。
問題是為什么在標準為 1bar.get_value()的第一種情況下回傳 0 ?#if我們如何解釋它?引擎蓋下發生了什么導致 0 而不是 42,即使std::move被呼叫來傳輸值 42?謝謝。
uj5u.com熱心網友回復:
人們普遍認為它std::move有一個誤導性的名稱:它實際上并不執行移動。相反,它執行一個強制轉換,類似于static_cast<T&&>1。
要執行移動,您需要呼叫移動建構式或移動賦值運算子。這不會發生在您的#if 1代碼分支中,但它確實發生在具有顯式建構式呼叫的另一個分支中。由于沒有標記建構式explicit,您也可以撰寫
bar_t bar = std::move(gen_foo(42)->m_bar);
這看起來像移動是由執行的,std::move但實際發生的是bar通過呼叫其移動建構式進行初始化。
重要的是,您的第一個代碼不涉及生命周期延長(即使沒有移動也可以使其作業)的原因是,需要系結生命周期延長才能作業的臨時物件是 的回傳值gen_foo(42),而不是gen_foo(42)->m_bar.
這是一個延長生命周期確實有效的示例(請注意,我們不需要,std::move因為gen_foo(42)它已經是一個右值):
std::unique_ptr<foo_t>&& foo = gen_foo(42); // extends the lifetime
bar_t& bar = foo->m_bar; // regular reference
而且,為了完整起見,以下 move-constructs foo。再一次std::move是不必要的,因為gen_foo(42)它已經是一個右值:
std::unique_ptr<foo_t> foo = gen_foo(42); // move construction
bar_t& bar = foo->m_bar; // regular reference
移動構造 astd::unique_ptr既便宜又容易,并且此代碼顯示了常見用法(實際上沒有理由對std::unique_ptr物件使用生命周期擴展)。
1實際實作稍微復雜一些。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/525556.html
標籤:C
