我正在编写一个将连接到数据库的类。所以我有一个全局变量std::shared_ptr<sql::Driver> driver;
,因为我正在尝试学习如何使用智能指针来做所有事情。但这总是会导致一个问题,到目前为止,每个智能指针都受到保护,因为 的析构函数sql::Driver
是受保护的。所以打电话driver.reset( )
总是会遇到问题。如何将智能指针与sql::Driver
?
4 回答
简而言之,某些类不打算由某些外部调用者(即您)管理。
有些类的设计方式是破坏作为副作用发生:
void finished() {
// Do something...
delete this;
}
在其他情况下,这些类可能由某个朋友类管理,例如实例管理器或某种类型。受保护的析构函数可能意味着您需要扩展该类以获得许可。
按照这些思路,单例类不能被实例化,也不能存储在任何类型的智能指针中,因为构造函数通常是私有的;
class Singleton {
private:
Singleton() { //...
}
};
这些类型的类与智能指针不兼容,因为它不允许正确的引用计数。
连接器/C++ 连接到 MySQL部分说您不必delete driver
明确说明,这就是您获得error: ‘virtual sql::Driver::~Driver()’ is protected
. 所以解决方案是使用哑指针driver
代替智能指针。(仅适用于driver
!)
和Connection
,Statement
并且ResultSet
对智能指针没有任何问题:
// 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
中没有删除。
如果它受到保护,则它要么是继承自,要么您应该调用静态 Destroy() 函数(或类似函数)进行销毁。对于前者,您可以执行以下操作:
class MyDriver : public sql::Driver
{
public:
virtual ~MyDriver() {} // calls sql::Driver::~Driver() implicitly
// ...
};
也许您的 SQL 库中的一些具体类可以为您实现这一点。在这种情况下,寻找如何使用它们。
对于销毁函数,您使用自定义删除器。假设是这样的:
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 和 non-virtual。
第三种选择是你的 sql::Driver 应该是一个单例,尽管 dtor 应该在那里仍然是私有的,除非它是为继承而设计的。
你试图做的是完全错误的。你提到如果你使用普通指针,你根本不会打电话delete
。连同析构函数 isprotected
的事实,暗示您没有指针值的所有权这一事实。
由于您没有所有权,因此您与unique_ptr
和/或无关shared_ptr
,它处理指向的值的唯一和共享所有权。
如果您坚持走那条路线,并增加相当大的开销以保持对您甚至不需要的东西的同步引用计数,那么您可以做到。两者都unique_ptr
可以shared_ptr
采用Deleter参数。正如您已经提到的那样,就您而言,这将是no-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{} };