C++;智能指针混淆 我知道在C++领域提倡使用智能指针。我有一个简单的程序如下 /* 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; }

C++;智能指针混淆 我知道在C++领域提倡使用智能指针。我有一个简单的程序如下 /* 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; },c++,c++11,sqlite,smart-pointers,C++,C++11,Sqlite,Smart Pointers,当我使用shared_ptr行编译时,它是成功的。从几个问题和答案中,我的理解是,应该首选unique_ptr,因为我不打算让对象共享资源。在这种情况下,最好的解决方案是什么?使用shared_ptr或回到旧的裸指针方法(new/delete)是一种不透明的结构(很像C中的文件)。你所拥有的只是它的声明,而不是它的定义。这意味着您不能在没有自定义删除程序的情况下直接在std::unique\u ptr中使用它。一般方法是@SomeProgrammerDudes的答案(接受它)。但是为了解决你的担

当我使用shared_ptr行编译时,它是成功的。从几个问题和答案中,我的理解是,应该首选unique_ptr,因为我不打算让对象共享资源。在这种情况下,最好的解决方案是什么?使用shared_ptr或回到旧的裸指针方法(new/delete)

是一种不透明的结构(很像C中的
文件
)。你所拥有的只是它的声明,而不是它的定义。这意味着您不能在没有自定义删除程序的情况下直接在
std::unique\u ptr
中使用它。

一般方法是@SomeProgrammerDudes的答案(接受它)。但是为了解决你的担忧,我发布了这个

您不应该返回原始新建和删除。既不是因为
sqlite3
是不透明类型,也不是因为
std::shared\u ptr
的开销。正如另一个答案所指定的那样,您使用
std::unique\u tr

唯一的区别是如何设置自定义删除程序。对于
std::unique_ptr
,它是类型定义的一部分,而不是运行时参数。所以你需要这样做:

struct sqlite3_deleter {
  void operator()(sqlite3* sql) {
    sqlite3_close_v2(sql);
  }
};

using unique_sqlite3 = std::unique_ptr<sqlite3, sqlite3_deleter>;
struct sqlite3\u deleter{
void运算符()(sqlite3*sql){
sqlite3_close_v2(sql);
}
};
使用unique_sqlite3=std::unique_ptr;
#包括
#包括
/*sqlite 3接口*/
结构sqlite3{};
外部无效sqlite3_关闭(sqlite3*);
外部内部sqlite3_打开(sqlite3**);
/*我们的样板*/
结构闭合器
{
void运算符()(sqlite3*p)常量
{
sqlite3_关闭(p);
}
};
使用sqlite3_ptr=std::unique_ptr;
/*便利制造功能*/
sqlite3_ptr make_sqlite()
{
sqlite3*buffer=nullptr;
int err=sqlite3\u打开(&buffer);
如果(错误){
抛出std::runtime_错误(“打开sqlite失败”);
}
返回sqlite3_ptr(缓冲区);
}
int main()
{
auto mysqlite=make_sqlite();
}
共享的解决方案 我学习C++和SQLite,所以我也有这个问题。读完这篇文章后,我试着从中找到一些答案。结果是一个工作示例和一个小型分析

  • 首先为智能指针创建自定义删除器
  • 然后,创建一个包含自定义删除器的空共享\u ptr
  • 然后,为DB处理程序创建一个空指针(
    sqlite3*DB;
  • 然后,打开/创建数据库
  • 将原始指针链接到共享指针
  • 在shared_ptr超出范围后,它也将删除原始指针
这是相当低效的(见结论),但这是我设法在sqlite3中使用智能指针的唯一方法,所以我决定将此作为一个答案发布

#包括
#包括
#包括
//自定义删除程序
自动删除sqlite3=[](sqlite3*pSqlite)
{

std::是的,从其他几个问题和答案中我也得到了。那么还有什么选择?@Amani创建一个自定义删除器(如果您不能直接使用)?即使不打算共享资源,使用共享\u ptr也会有成本吗?@Amani是的,即使只有一个实例,共享状态仍然会被分配。@Someprogrammerdude值得指出的是,
std::shared\u ptr
不需要客户删除器的原因很简单,
db
是使用特殊构造函数重载。使用
unique\u ptr
时,您必须使用模板参数指定自定义删除程序,但对于
shared\u ptr
,可以使用构造函数对每个对象执行此操作。尝试使用其他重载进行构造,当编译器发现
sqlite3
对象缺少destr时,它也不会编译构造函数声明。您会发现new/delete方法也不是一个选项。@user207933-Plus,
decltype(sqlite3\u close)
这里是
void(sqlite*)
,一个不完整的类型。@user207933我更喜欢构建自己的类型,以便在析构函数中执行的操作由我显式控制。@StoryTeller
void(sqlite*)
不是不完整的,即使
sqlite*
是不完整的,除非我弄错了。@user207933-这是一种函数类型。为了定义对象,它是不完整的。我要说的是,它不会解析为
打印
。@Holt&StoryTeller不介意我以前的评论,函数指针似乎工作得很好。我是缩写由于您的评论和我的测试失败,我对此表示怀疑,但这只是因为删除程序不会在
nullptr
上调用,所以我的测试是错误的。
std::unique\u ptr
似乎工作得很好:非常感谢您提供的示例。
struct sqlite3_deleter {
  void operator()(sqlite3* sql) {
    sqlite3_close_v2(sql);
  }
};

using unique_sqlite3 = std::unique_ptr<sqlite3, sqlite3_deleter>;
#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();
}