encupsalator对象的C ++规则为3

时间:2013-12-17 20:33:57

标签: c++ object encapsulation

以下是我的情景:

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 对象。在这种形式中,似乎它可能是一种不安全的方法,因为如果我复制对象并将其销毁,则复制的对象处于无效状态。

在您看来,最好的方法是什么?我在想单身课,但我不确定。

3 个答案:

答案 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;

[0] http://en.cppreference.com/w/cpp/memory/shared_ptr

答案 2 :(得分:1)

除非有充分理由不这样做,否则请禁用复制构造函数和赋值运算符,并且不允许复制。如果有充分的理由允许复制,那么探索这个原因将有助于您了解在存在副本时您真正想要的语义,这应该导致设计。