据我所知,在C ++领域,它主张使用智能指针。我有一个简单的程序如下。
**startsWith()**
当我使用unique_ptr行编译时收到错误消息:
/* main.cpp */
#include <iostream>
#include <memory>
using namespace std;
/* SQLite */
#include "sqlite3.h"
int main(int argc, char** argv)
{
// unique_ptr<sqlite3> db = nullptr; // Got error with this
shared_ptr<sqlite3> db = nullptr;
cout << "Database" << endl;
return 0;
}
当我使用shared_ptr行编译时,它成功了。从几个问题和答案我的理解是unique_ptr应该是首选,因为我不打算让对象共享资源。在这种情况下,最佳解决方案是什么?使用shared_ptr还是回到裸指针的旧方法(new / delete)?
答案 0 :(得分:5)
一般方法是@ SomeProgrammerDudes的答案(接受它)。但是为了解决你的问题,我发布了这个。
你不应该回到raw new并删除。也不是因为sqlite3
是一个不透明的类型,也不是因为std::shared_ptr
的开销。作为指定的其他答案,您使用std::unique_tr
。
唯一的区别是您如何设置自定义删除器。对于std::unique_ptr
,它是类型定义的一部分,而不是运行时参数。所以你需要做这样的事情:
struct sqlite3_deleter {
void operator()(sqlite3* sql) {
sqlite3_close_v2(sql);
}
};
using unique_sqlite3 = std::unique_ptr<sqlite3, sqlite3_deleter>;
答案 1 :(得分:4)
sqlite3
是不透明结构(非常类似于C中的FILE
)。你所拥有的只是它的声明,而不是它的定义。这意味着如果没有自定义删除工具,您无法直接在std::unique_ptr
中使用它。
答案 2 :(得分:1)
#include <memory>
#include <stdexcept>
/* sqlite 3 interface */
struct sqlite3 {};
extern void sqlite3_close(sqlite3*);
extern int sqlite3_open(sqlite3**);
/* our boilerplate */
struct closer
{
void operator()(sqlite3* p) const
{
sqlite3_close(p);
}
};
using sqlite3_ptr = std::unique_ptr<sqlite3, closer>;
/* handy maker function */
sqlite3_ptr make_sqlite()
{
sqlite3* buffer = nullptr;
int err = sqlite3_open(&buffer);
if (err) {
throw std::runtime_error("failed to open sqlite");
}
return sqlite3_ptr(buffer);
}
int main()
{
auto mysqlite = make_sqlite();
}
答案 3 :(得分:1)
shared_ptr
我正在学习C ++和SQLite,所以我也有这个问题。阅读这篇文章后,我尝试了一些答案。结果是一个可行的示例和一个简短的分析。
sqlite3 * DB;
)创建一个空指针这效率不高(请参见结论),但这是我设法在sqlite3中使用智能指针的唯一方法,因此我决定将其发布为答案。
#include <iostream>
#include<sqlite3.h>
#include<memory>
//Custom deleter
auto del_sqlite3 = [](sqlite3* pSqlite)
{
std::cout << "Calling custom deleter." << std::endl;
sqlite3_close_v2(pSqlite);
};
int main()
{
//Uncomment to run
//const char* dir = "C:\\test\\db_dir\\test.db"
openOrCreateDB(dir);
return 0;
}
int openOrCreateDB(const char* dirName)
{
std::shared_ptr<sqlite3> DB(nullptr, del_sqlite3);//custom deleter
auto pDB = DB.get();
{
int exit = sqlite3_open(dirName, &pDB);
DB.reset(pDB);// Replace nullptr with pDB and link
}
return 0;
}
使用智能指针的主要原因是自动执行内存管理并避免内存泄漏。因此,如果我们正在考虑使用new
和delete
在免费存储区上分配内存,则会发生这种情况。
但是我在免费存储区中分配数据库处理程序的所有尝试都失败了。
sqlite3* DB = new sqlite3;
int openOrCreateDB(const char* dirName)
{
sqlite3* DB = new sqlite3;//E0070: Incomplete type not allowed
int exit = sqlite3_open(dirName, &DB);
sqlite3_close(DB);
return 0;
}
share_ptr
static int openOrCreateDB(const char* dirName)
{
std::shared_ptr<sqlite3> DB(new sqlite3, del_sqlite3);// Incomplete type not allowed
auto pDB = DB.get();
{
int exit = sqlite3_open(dirName, &pDB);
DB.reset(pDB);
}
return 0;
}
make_shared
我什至没有尝试。在 Meyers的有效现代C ++ 中,第21项清楚地表明,您不能使用make_shared
在具有自定义删除器的堆上构造智能指针。
也许我做错了,但是SQLite似乎不喜欢在堆上分配数据库处理程序(sqlite3对象)。那么为什么还要使用智能指针呢?即使在堆栈上分配db处理程序,智能指针也会占用更多内存和更多代码行。
使用智能指针的另一个原因是管理所有权。但是,在sqlite3中,工作流程非常重复:在例行程序中:
所以我看不到为什么要在此工作流程之外传递一个数据库处理程序。
我的建议是继续使用原始指针,并使用sqlite3_close(sqlite3 * ptr)
破坏它们。