我正在将我的代码转换为使用unique_ptr而不是指针。我正在尝试创建一个sqlite3_statement的unique_ptr,它自动在其自定义删除器中调用函数sqlite3_finalize(sqlite3_stmt * pStmt)。如何在头文件中使用它?我在这里完全不知所措,欢迎任何帮助。感谢。
在igleyy的帮助下(当出于某种原因调用删除器时,他的解决方案给了我内存访问错误)我想出了这个似乎工作且看起来很优雅的解决方案;
Datasource.h
#pragma once
#include <sqlite\sqlite3.h>
#include <string>
#include <vector>
#include <memory>
class Datasource
{
void statementDeleter(sqlite3_stmt* object);
std::unique_ptr<sqlite3_stmt, std::function<void(sqlite3_stmt*)>> statement;
Datasource(Datasource const &);
Datasource &operator=(Datasource const &);
public:
Datasource(void);
~Datasource(void);
};
Datasource.cpp
#include "Datasource.h"
Datasource::Datasource(void) :
statement(nullptr,std::bind(&Datasource::statementDeleter,this,std::placeholders::_1))
{
}
void Datasource::statementDeleter(sqlite3_stmt * s)
{
sqlite3_finalize(s);
}
Datasource::~Datasource(void)
{
}
答案 0 :(得分:2)
你可以像这样编写简单的lambda表达式:
auto d = [](sqlite3_stmt* stmt) { sqlite3_finalize(stmt); };
std::unique_ptr<sqlite3_stmt, decltype(d)> statement(new sqlite3_stmt, d);
<强>解释强>
使用lambda表达式创建自定义删除器,并将其存储在自动识别类型的变量中。 decltype
用于获取表达式类型(在您创建unique_ptr
时必须提供的表达式,以便将其与自定义删除程序一起提供)。
修改强>
您的Datasource类代码中有两个语句变量,您需要重命名其中一个。您无法像这样初始化d
和第一个statement
变量。我认为在这种情况下不可能使用auto,但我们可以使用std::function
。将auto d ...
与std::function<void(sqlite3_stmt*)> d;
一起添加并替换。在构造函数初始化列表中初始化d
。
将statement
更改为std::unique_ptr<int, decltype(d)> statement;
并在构造函数初始化列表中初始化它。
Datesource::Datasource() :
d([](sqlite3_stmt* stmt) { sqlite3_finalize(stmt); }),
statement(new sqlite3_stmt) { /* constructor code */ }
答案 1 :(得分:0)
我会说独特的ptr不是这种方式。我之所以这样说是因为stdlib已经与名为lock_guard
的互斥锁已经并行了,你不能使用lock_guard
,但这个想法是一样的。创建一个名为sql_stmt_guard
的类或其他类。基本上它如何工作是在构造它将在语句上执行设置方法,析构函数将调用sqlite3_finalize
。 c ++中lock_guard
(或出现情况时unique_lock
)被认为是惯用的,非常有用,因为RAII可以保证unlock
方法可以运行,并保证你的sqlite3_finalize
将被调用
答案 2 :(得分:0)
只需定义一个释放语句的自定义删除器:
struct sqlite_finalizer {
void operator()(sqlite3_stmt*& s) const {
sqlite3_finalize(s);
// ... anything else.
}
};
然后为它创建一个自定义typedef:
using sqlite3_handle = std::unique_ptr<sqlite3_stmt, sqlite_finalizer>;
sqlite3_handle handle;