如何将sql::driver与智能指针结合起来

How to combine sql::driver with smart pointers?

本文关键字:智能 指针 结合 起来 driver sql      更新时间:2023-10-16

我正在编写一个将连接到数据库的类。所以我有一个全局变量std::shared_ptr<sql::Driver> driver;因为我想学习如何用智能指针做所有的事情。但是,到目前为止,对于每个智能指针,这总是以一个问题告终,因为sql::Driver的析构函数是受保护的。所以像driver.reset( )这样的电话总是以问题告终。如何将智能指针与sql::Driver相结合?

简而言之,有些类不打算由某些外部调用者(即您)管理。

有些类被设计成销毁作为副作用发生:

void finished() {
  // Do something...
  delete this;
}

在其他情况下,这些类可能由某个友类(例如实例管理器或其他类型)管理。受保护的析构函数可能意味着您需要扩展该类以获得权限。

这样,单例类既不能实例化,也不能存储在任何类型的智能指针中,因为构造函数通常是私有的;

class Singleton {
private:
  Singleton() {  //...
  }
};

这些类型的类与智能指针不兼容,因为它不允许正确的引用计数。

连接器/c++连接到MySQL的部分说,你不需要显式地delete driver,这就是为什么你得到error: ‘virtual sql::Driver::~Driver()’ is protected。因此,解决方案是为driver使用哑指针而不是智能指针。(仅限driver !)

Connection, StatementResultSet没有智能指针的问题:

// a dumb pointer is used here intentionally, no need to delete it
sql::Driver* driver = get_driver_instance();
// shared_ptr also works
unique_ptr<sql::Connection> con( driver->connect("tcp://127.0.0.1:3306", "root", "root") );

注意,在Connector/c++ Complete Example 1和Connector/c++ Complete Example 2中,driver没有被删除。

你想做的只是完全错误的。您提到,如果使用普通指针,则根本不会调用delete。这一点,再加上析构函数是protected这一事实,暗示了这样一个事实,即您没有指针值的所有权。

由于您没有所有权,因此您与unique_ptr和/或shared_ptr无关,它们处理指向的值的唯一和共享所有权。

如果你坚持走这条路,并且为一些你甚至不需要的东西增加相当大的开销来保持同步的引用计数,那么你可以这样做。unique_ptrshared_ptr都可以接受Deleter参数。在您的情况下,正如您已经提到的,它将是一个无op

struct noop_deleter
{
    void operator ()(void const* ptr) const { /*no-op*/ };
};
shared_ptr<sql::driver>{ driver_ptr, noop_deleter{} };
unique_ptr<sql::driver, noop_deleter>{ driver_ptr, noop_deleter{} };

如果它是受保护的,它要么被继承,要么你应该调用一个静态的Destroy()函数(或类似的)来销毁它。对于前者,您可以执行如下操作:

class MyDriver : public sql::Driver
{
public:
    virtual ~MyDriver() {} // calls sql::Driver::~Driver() implicitly
    // ...
};
也许SQL库中的一些具体类为您实现了这一点。在这种情况下,寻找如何使用它们。

对于destroy函数,使用自定义删除器。假设如下:

namespace sql
{
    class Driver
    {
    public:
        static Driver* Create(); // factory
        static void Destroy( Driver* );
        // ...
    protected:
        Driver();
        virtual ~Driver();
    };
}

你会这样做:

std::shared_ptr<sql::Driver> driver( 
    sql::Driver::Create(), 
    sql::Driver::Destroy );
但是,一般来说,析构函数应该是public和virtual,或者private和非virtual。

第三种选择是你的sql::Driver应该是单例的,尽管dr仍然应该是私有的,除非它是为继承而设计的。