2016-08-25 104 views
0

我有一個數據庫類,顯式構造函數嘗試連接到基於傳入的標誌的數據庫,如果失敗則拋出。這是不希望的(數據庫可能不是由另一個應用程序創建的),所以我添加了一個空構造函數和默認的移動構造函數。在工具類中,我一直等到數據庫被創建並移動一個新的數據庫。默認移動構造函數

在單元測試中,我看到database_utils::connected()在移動之前返回false,在移動之後返回true。但是,如果我調用一個使用數據庫的函數,我會得到一個library routine called out of sequence錯誤。這表明我沒有打開數據庫或格式不正確的select語句,但構造函數和析構函數按照正確的順序調用,並且在創建數據庫,填充它和select語句工作的地方對數據庫本身進行了單元測試。

所以我的問題:默認移動實際上是否移動它?如果不是,我需要做什麼才能獲得預期的行爲?

示例代碼:

class database 
{ 
    database() : connected_(false), database_(nullptr) { } 
    database(/* params */) : connected_(false), database_(nullptr) { 
     /* attempt connection, throw on fail */ 
     connected_ = true; 
    } 
    database(database& other) = default; 
    database(database&& other) = default; 
    database& operator=(database&& other) = default; 
    ~database() { /* clean up */ } 
    operator bool() const { return connected_; } 

    bool connected_; 
    sqlite3* database_; 
}; 

class database_utils 
{ 
    database_utils() : db_() { } 
    void connect() { 
     db_ = std::move(database(/*params*/)); 
    } 
    bool connected() { return db_; } 
    void example_select(/* params */) { 
     /* use db_ */ 
    } 
    database db_; 
}; 
+0

如果您想驗證您的移動構造函數正在被調用,請在其中添加一條調試語句,並查看它是否出來。您當然知道,默認構造函數中沒有任何東西會使得從移動對象的指針(如'database_',這看起來像一個錯誤)變爲空值。你需要編寫自己的移動構造函數,這是正確的。 –

+0

[OT]:複製構造函數通過const引用取其arg。 – Jarod42

+1

您可能希望移動構造函數重置已移動的指針以避免雙重清理。 – Jarod42

回答

2

默認的移動構造函數做移動的一切。

但是database_是指針。指針移動實際上是複製。

然後在析構函數中,database_將被刪除。由於database_指向相同的內存位置,因此database_將指向超空間,因此「新」對象將處於非穩定狀態。

如果您可以將database_更改爲智能指針,則默認的移動構造函數可以正常工作。

或者,製作您自己的移動構造函數來移動所有內容,並將database_設置爲nullptrconnected_false

+0

我認爲一個指針移動會交換,所以如果a-> 0x0000和b-> 0x1234會變成a-> 0x1234和b-> 0x0000。 –

+0

不,這是不正確的。如果你做自己的移動構造函數,交換會很好,但默認的移動構造函數不會交換。 – Nick