2010-07-18 6 views
3

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

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, когда вам нужно назначить свой ресурс другой переменной?

ответ

9

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

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); 
} 
+1

+1 Для обозначения пользовательского делетера. – AraK

+1

выглядит как лишний мусор в вашем ответе: строка ', destroy_connection())', похоже, не принадлежит. –

+0

@Ben: Ой, спасибо - не знаю, как я получил это там. –

3

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

0

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

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

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

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