2

データベース クラスがあり、明示的なコンストラクターは、渡されたフラグに基づいてデータベースに接続しようとします。失敗すると、スローされます。これは望ましくない (データベースが別のアプリによって作成されていない可能性がある) ため、空のコンストラクターとデフォルトの移動コンストラクターを追加しました。ユーティリティ クラスでは、データベースが作成されるまで待ってから、新しいデータベースを移動します。

単体テストでは、database_utils::connected()移動前に false が返され、移動後に true が返されることがわかります。ただし、データベースを使用する関数を呼び出すと、library routine called out of sequenceエラーが発生します。これは、データベースまたは不正な形式の選択ステートメントを開いていないことを示唆していますが、コンストラクターとデストラクタは正しい順序で呼び出され、データベースを作成してデータを入力し、選択ステートメントが機能するデータベース自体の単体テストがあります。

だから私の質問:デフォルトの動きは実際にそれを動かしていますか?そうでない場合、期待される動作を得るために何をする必要がありますか?

サンプルコード:

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_;
};
4

1 に答える 1

5

デフォルトの移動コンストラクターはすべてを移動します。

ただしdatabase_ポインタです。ポインタの移動は実際にはコピーです。

次に、デストラクタで、database_削除されます。

「古い」オブジェクトと「新しい」オブジェクトの両方database_が同じメモリ位置を指すため、「新しい」オブジェクトはdatabase_ハイパースペースを指すため、不安定な状態になります。

database_スマート ポインターに変更できる場合は、既定の移動コンストラクターが適切に機能します。

database_または、すべてを移動してtonullptrおよびconnected_to に設定する独自の移動コンストラクターを作成しますfalse

于 2016-08-25T13:19:19.367 に答える