以下是我的情景:
class Database {
public:
Database();
~Database();
void close();
...
private:
sqlite3 *database; //SQLITE3 OBJECT
bool isOpenDb;
...
};
Database::Database() {
database = 0;
filename = "";
isOpenDb = false;
}
Database::~Database() {
close();
}
void Database::close() {
sqlite3_close(database);
isOpenDb = false;
}
当数据库对象被销毁时,我希望关闭 sqlite3 对象。在这种形式中,似乎它可能是一种不安全的方法,因为如果我复制对象并将其销毁,则复制的对象处于无效状态。
在您看来,最好的方法是什么?我在想单身课,但我不确定。
答案 0 :(得分:5)
让您的课程不可复制。在C ++ 11中:
class Database {
public:
Database(const Database&) = delete;
Database& operator=(const Database&) = delete;
};
在C ++ 03中:
class Database {
private: // inaccessible
Database(const Database&);
Database& operator=(const Database&);
};
或者与Boost:
#include <boost/noncopyable.hpp>
class Database : private boost::noncopyable {
};
在C ++ 11中,我还会通过给它一个MoveConstructor和Move赋值运算符来创建对象Movable
。在那里你可以将句柄(或你的数据库给你的任何东西)分配给新对象,并在旧对象中使用一些标志来表示不需要关闭任何东西。
不要忘记实施swap
!
class Database {
// This might look odd, but is the standard way to do it without a namespace.
// If you have a namespace surrounding Database, put it there.
friend void swap(Database& a, Database& b) { /* code to swap a and b */ }
};
另外:在析构函数中将某些值设置为false无效。什么都不应该看到变化。
或将unique_ptr
/ shared_ptr
与自定义删除器一起使用:
struct CloseDatabase {
void operator()(sqlite* x) { sqlite3_close(x); }
};
typedef std::unique_ptr<sqlite3, CloseDatabase> Database;
答案 1 :(得分:2)
考虑到您的应用程序是单线程的,您可以使用共享指针[0]。
复制构造函数将是微不足道的,当类的最后一个实例化被销毁时,对象将被销毁。
private:
std::shared_ptr<sqlite3> database;
编辑:正如pmr所指出的,在这种情况下需要自定义删除器来关闭数据库。例如一个简单的lambda:
database = std::shared_ptr<sqlite3>(new database,
[](sqlite3 *db)
{ db->close; delete db; });
或者您可以将仿函数用作删除器。
Singleton会让你的课程不可复制,如果这是你想要的,你可以这样做。
或者只是禁用复制构造函数和复制操作符(并移动等效项)。 C ++ 11提供关键字delete来执行此操作。
Database(const Database &) = delete;
Database & operator =(const Database &) = delete;
Database(Database &&) = delete;
Database & operator =(Database &&) = delete;
答案 2 :(得分:1)
除非有充分理由不这样做,否则请禁用复制构造函数和赋值运算符,并且不允许复制。如果有充分的理由允许复制,那么探索这个原因将有助于您了解在存在副本时您真正想要的语义,这应该导致设计。