C++ SQLite和BOOST\u范围\u退出\u全部

C++ SQLite和BOOST\u范围\u退出\u全部,c++,sqlite,C++,Sqlite,例如,为什么SQLite C接口在使用BOOST\u SCOPE\u EXIT\u ALL时需要通过引用传递指针 假设我有以下代码: #include <boost/scope_exit.hpp> #include <sqlite3.h> #include <cstdlib> #include <iostream> int main() { sqlite3* db; BOOST_SCOPE_EXIT_ALL(db) { i

例如,为什么SQLite C接口在使用
BOOST\u SCOPE\u EXIT\u ALL
时需要通过引用传递指针

假设我有以下代码:

#include <boost/scope_exit.hpp>

#include <sqlite3.h>

#include <cstdlib>
#include <iostream>

int main()
{
  sqlite3* db;
  BOOST_SCOPE_EXIT_ALL(db)
  {
    if (sqlite3_close(db) != SQLITE_OK)
    {
      std::cerr << sqlite3_errmsg(db) << '\n';
    }
  };

  if (sqlite3_open(":memory:", &db) != SQLITE_OK)
  {
    std::cerr << sqlite3_errmsg(db) << '\n';
    return EXIT_FAILURE;
  }

  sqlite3_stmt* prepared_stmt = NULL;
  BOOST_SCOPE_EXIT_ALL(db, prepared_stmt)
  {
    if (sqlite3_finalize(prepared_stmt) != SQLITE_OK)
    {
      std::cerr << sqlite3_errmsg(db) << '\n';
    }
  };
  if (sqlite3_prepare_v2(db, "CREATE TABLE IF NOT EXISTS foo(bar TEXT, baz TEXT)", -1, &prepared_stmt, 0) != SQLITE_OK)
  {
    std::cerr << sqlite3_errmsg(db) << '\n';
    return EXIT_FAILURE;
  }

  if (sqlite3_step(prepared_stmt) != SQLITE_DONE)
  {
    std::cerr << sqlite3_errmsg(db) << '\n';
    return EXIT_FAILURE;
  }
}

它说

由于未完成的语句或未完成的备份,无法关闭

尝试调用
sqlite3\u close
函数时

如果我也通过引用传递了
prepared\u stmt
,它将按预期工作:

BOOST_SCOPE_EXIT_ALL(db, &prepared_stmt)
为什么??我认为SQLite库只抱怨
db
prepared\u stmt
指向的地址

提前感谢。

main()中的第一行

这可能就是sqlite3_close()崩溃的原因。编译器可能正在为声明的指针重用内存位置,并且不一定使用空位置或将其设为空。因此,对sqlite3_close()的调用接收到一个伪指针

州政府的文件:

sqlite3_close(C)和sqlite3_close_v2(C)的C参数必须为 从中获取的NULL指针或sqlite3对象指针 sqlite3_open()、sqlite3_open16()或sqlite3_open_v2(),而不是 以前关闭过。使用调用sqlite3\u close()或sqlite3\u close\u v2() 空指针参数是无害的no-op

因此,根据上述声明,以下代码应删除崩溃:

 sqlite3* db = nullptr;
当然,如果您只是完全删除了这段不必要的代码,所有这些都是没有意义的:

BOOST_SCOPE_EXIT_ALL(db)
{
  if (sqlite3_close(db) != SQLITE_OK)
  {
    std::cerr << sqlite3_errmsg(db) << '\n';
  }
};
BOOST\u SCOPE\u EXIT\u ALL(分贝)
{
如果(sqlite3\u关闭(db)!=SQLITE\u正常)
{

std::cerr我有点困惑——为什么要在数据库被打开之前调用sqlite3_close()?我只是不确定我是否认为这段代码的原因是main()函数中的第一件事。我遗漏了什么吗?@Amadeus--“无论在打开时是否发生错误,与数据库连接句柄关联的资源应在不再需要时通过将其传递给sqlite3_close()来释放”“必须是空指针或从sqlite3_open()获取的sqlite3对象指针”“--在我的例子中,
sqlite3\u open
返回
SQLITE\u OK
。那么怎么了?在调用sqlite3\u open()[line 19]之前,您正在调用sqlite3\u close()[line 13]。整个sqlite3\u close()块(我在回答中复制的)应该放在main()的末尾,不是开始。实际上,此实例可能是使用“goto”的好机会。使用“goto标签”代替“return EXIT_FAILURE”然后让标签在最后返回退出失败并关闭数据库。我使用我提到的概念用未经测试的函数版本更新了我的答案。我不是sqlite3专家,但我相当肯定这会得到您想要的结果。
sqlite3* db;
 sqlite3* db = nullptr;
BOOST_SCOPE_EXIT_ALL(db)
{
  if (sqlite3_close(db) != SQLITE_OK)
  {
    std::cerr << sqlite3_errmsg(db) << '\n';
  }
};
int main()
{
sqlite3* db = nullptr;

if (sqlite3_open(":memory:", &db) != SQLITE_OK)
    goto ERROR_OCCURRED;

sqlite3_stmt* prepared_stmt = nullptr;
if (sqlite3_finalize(prepared_stmt) != SQLITE_OK)
    std::cerr << sqlite3_errmsg(db) << '\n';

if (sqlite3_prepare_v2(db, "CREATE TABLE IF NOT EXISTS foo(bar TEXT, baz TEXT)", -1, &prepared_stmt, 0) != SQLITE_OK)
    goto ERROR_OCCURRED;

if (sqlite3_step(prepared_stmt) != SQLITE_DONE)
    goto ERROR_OCCURRED;

if (sqlite3_close(db) != SQLITE_OK)
{   
     std::cerr << sqlite3_errmsg(db) << '\n';
     sqlite3_close(db);
     return EXIT_FAILURE;
}
return 0;

ERROR_OCCURRED:
    std::cerr << sqlite3_errmsg(db) << '\n';
    sqlite3_close(db);
    return EXIT_FAILURE;
}