2016-07-03 48 views
2

移動構建一個對象通過新的位置不是UB嗎?移動構建對象與新的位置

比方說,我有這樣的代碼:

class Foo { 
public: 
    Foo() { foo_ = new int; } 
    ~Foo() { delete foo_; } 
    Foo(Foo &&f) { 
     foo_ = std::swap(f.foo_, foo_); 
    } 
private: 
    int* foo_; 
} 

void bar() { 
    void* pMem = malloc(sizeof(Foo)); 
    Foo f1; 
    // move-construct with placement new: 
    new((Foo*)pMem) Foo(std::move(f1)); // f2 in *pMem 

    // now f1 will contain a pointer foo_ of undefined value 
    // when exiting scope f1.~Foo(){} will exhibit UB trying to delete it 
} 

如果不是很明顯,F1的成員foo_將被放置新構造第二FOO後有一個未定義的值,進入施工(這不確定的價值來自於未初始化富F2的它的移動構造函數裏面foo_因爲值是交換

因此,離開酒吧的範圍時(),F1的析構函數會嘗試刪除無效的(未初始化的)指針。

+0

Placement或其他'new'獲取內存。構造函數將內存轉換爲對象。 'new'不關心你如何處理內存。構造函數不關心你如何獲得內存。是的,這種行爲沒有消除,但與分配違規對象的方式無關。可以是自動的或任何其他類型的。 –

回答

5

這與放置新物品無關。此代碼將有相同的問題:

void bar() { 
    Foo f1; 
    Foo f2(std::move(f1)); 
} 

構造的對象,他們最終都會被破壞,因此,如果您使用投放新的或沒有也沒關係,你的舉動,通過構造離開食堂了從無效狀態移動而來的對象。從對象移動並不意味着它不會被破壞。它會。當你離開它時,你必須讓一個有效的對象落後。

Foo(Foo &&f) : foo_(nullptr) { 
    std::swap(f.foo_, foo_); 
} 

將修復該錯誤。

+0

有趣的是,我不知道你可以使用移動構造函數的初始化列表。這將確實修復錯誤。 –

+0

@BogdanIonitza:它們可以是* any *構造函數的一部分。移動構造函數在這方面並不特別。 –

+0

@NicolBolas現在我想到了它是有道理的。儘管如此,我從來沒有想過 –