2016-08-25 4 views
0

У меня есть класс базы данных, и явный конструктор пытается подключиться к базе данных на основе пропущенных флагов, если он терпит неудачу, то он бросает. Это нежелательно (база данных не может быть создана другим приложением), поэтому я добавил пустой конструктор и конструкторы перемещения по умолчанию. В классе утилиты я жду, пока база данных не будет создана и не переместят новую.Default move constructor

В модульных тестах я вижу, что database_utils::connected() возвращает false до того, как я вернусь и вернусь после перемещения. Однако, если я вызываю функцию, которая использует базу данных, я получаю ошибку 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]: конструктор копирования принимает аргумент arg по ссылке const. – Jarod42

+1

Возможно, вы захотите, чтобы конструктор перемещения сбросил указатель перемещения, чтобы избежать двойной очистки. – Jarod42

ответ

2

По умолчанию шаг конструктора двигаются все.

Однако database_ является указателем. Перемещение указателя на самом деле является копией.

Затем в деструкторе database_ будет удален.

Поскольку «старый» и «новый» объекты database_ указывает на то же место в памяти, «новый» объект будет находиться в нестабильном состоянии, так как database_ будет указывать на гиперпространство.

Если вы можете изменить database_, чтобы быть умным указателем, конструктор перемещения по умолчанию будет работать хорошо.

В качестве альтернативы, сделать свой собственный конструктор перемещения, переместить все и установить database_ в nullptr и connected_ к false.

+0

Я думал, что перемещение указателя будет заменой, поэтому, если a-> 0x0000 и b-> 0x1234 станут a-> 0x1234 и b-> 0x0000. –

+0

нет, это неправильно. если вы сделаете свой собственный конструктор перемещения, swap будет отличным, но конструктор перемещения по умолчанию не будет выполнять обмен. – Nick

Смежные вопросы