RAII и назначение - PullRequest
       2

RAII и назначение

3 голосов
/ 18 июля 2010

Я создал следующий класс для соединения sqlite3:

class SqliteConnection
{
public:
    sqlite3* native;

    SqliteConnection (std::string path){
        sqlite3_open_v2 (path.c_str(), &native, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
    }

    ~SqliteConnection (){
        sqlite3_close(native);
    }
}

и затем можно инициализировать соединение следующим образом

SqliteConnection conn("./database.db");

Однако я хотел бы иметь возможность поделитьсяэто соединение, сохраните его как член в классах и т. д., и проблема в операторе присваивания по умолчанию operator=.Выполнение чего-то вроде

SqliteConnection conn("./database.db");
SqliteConnection conn1 = conn;

приведет к двум вызовам sqlite3_close для указателя базы данных, поскольку каждая переменная выходит из области видимости.Как вы преодолеваете эту проблему с RAII, когда вам нужно присвоить свой ресурс другой переменной?

Ответы [ 3 ]

9 голосов
/ 18 июля 2010

Для общих ресурсов вы должны следить за тем, существуют ли ссылки на них, например, используя подсчет ссылок . Одна реализация - boost::shared_ptr с пользовательским средством удаления:

class SqliteConnection {
    boost::shared_ptr<sqlite3> native;
public:
    SqliteConnection(const std::string& path) 
      : native(init_connection(path), &destroy_connection)
    {}
    // ...
};

sqlite3* init_connection(const std::string& path) {
    // ...
    return ptr;
}

void destroy_connection(sqlite3* p) {
    sqlite3_close(p);
}
3 голосов
/ 18 июля 2010

Поместите соединение в shared_ptr.При назначении все, что вам нужно сделать, это назначить «shared_ptr» для совместного владения ресурсом (соединение).В противном случае вам нужно реализовать совместное владение для вашего класса, что уже было сделано в boost и включено в C ++ 0x.

0 голосов
/ 18 июля 2010

У вас есть четыре основных варианта:

  • Использовать подсчет ссылок, вероятно, через shared_ptr.Это наименее эффективное, но наиболее общее решение.
  • Запретить назначения.Не позволяйте пользователю копировать объект SQLite.Сделайте оператор присваивания и копируйте конструкторы приватными.Тогда пользователям придется вместо этого передавать указатели или ссылки.
  • Пусть назначение «украдет» ресурс.Это то, что делает auto_ptr.a = b приводит к тому, что a становится владельцем соединения b, а для b устанавливается нулевое значение как пустой непригодный объект.
  • Создает новое соединение, когда копиясоздано.Это зависит от API sqlite, обеспечивающего необходимую функциональность.В частности, запросы и другие специфичные для соединения данные также могут быть скопированы, что может быть нецелесообразно
...