2016-08-25 122 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