使用外部定义的自定义删除器在头文件中定义唯一指针

时间:2013-11-11 17:33:53

标签: c++ unique-ptr

我正在将我的代码转换为使用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)
{
}

3 个答案:

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