1

我正在将我的代码转换为使用 unique_ptr 而不仅仅是指针。我正在尝试为 sqlite3_statement 创建一个 unique_ptr,它会在其自定义删除器中自动调用函数 sqlite3_finalize(sqlite3_stmt *pStmt)。我怎样才能让它在我的头文件中工作?我在这里完全不知所措,欢迎任何帮助。谢谢。

在 igleyy 的大力帮助下(当出于某种原因调用删除器时,他的解决方案给了我内存访问错误)我想出了这个似乎有效且看起来很优雅的解决方案;

数据源.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);
};

数据源.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)
{
}
4

3 回答 3

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在构造函数初始化列表中初始化。更改statementstd::unique_ptr<int, decltype(d)> statement;并在构造函数初始化列表中对其进行初始化。

Datesource::Datasource() : 
  d([](sqlite3_stmt* stmt) { sqlite3_finalize(stmt); }), 
  statement(new sqlite3_stmt) { /* constructor code */ }
于 2013-11-11T17:37:45.157 回答
1

只需定义一个释放语句的自定义删除器:

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;
于 2013-11-11T17:44:23.907 回答
0

我会说唯一的 ptr 不是继续这个的方法。我这样说是因为 stdlib 已经有一个与此并行的互斥锁lock_guard,你不能使用lock_guard,但想法是一样的。做一个叫sql_stmt_guard什么的类。基本上它的工作方式是在构造上它会在语句上执行 setup 方法,而析构函数会调用sqlite3_finalize. lock_guard(或unique_lock当情况出现时)在 c++ 中被认为是惯用的并且非常有用,因为 RAII 为您提供了该unlock方法将运行的保证,并为您提供了您sqlite3_finalize将被调用的保证

于 2013-11-11T17:38:14.830 回答