我目前正在尝试调用sqlite3库函数,它希望我将它传递给sqlite3**
。
这是我目前的代码。我有一个工作部分,一部分给我一个错误:
sqlite3 *sqlite = m_db.get();
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite))
{
}
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &(m_db.get()) ))
{
}
我的m_db
字段如下所示:
std::unique_ptr<sqlite3> m_db = nullptr;
在我展示的两个例子中,第一个是完美的。但是,第二个给了我这个错误。请注意,这来自&(m_db.get())
部分:
“Address expression must be an lvalue or a function designator”
我读了一些关于左值和左值的内容,但我似乎无法弄清楚为什么这种语法不可能。据我所知,现在问题是.get()操作的返回值只是一个临时表达式结果,因此在内存中没有可识别的位置,我可以从中获取地址。 / p>
我想,必须有一种方法可以在一个声明中实现这一点。
任何人都可以向我解释为什么这不起作用以及我如何解决它?
答案 0 :(得分:8)
&
运算符只能与左值一起使用(或在指向成员时使用限定的id)。表达式m_db.get()
是一个右值,因为它按值返回指针,而不是通过引用返回,因此您无法获取其地址。
unique_ptr
没有提供访问基础指针作为参考的方法,您需要在第一个示例中的某处存储副本。
答案 1 :(得分:3)
智能指针存储指针并在get上返回。你想在这里做的是相反的:你得到一个来自{{1}}的指针,并希望将它存储在一个智能指针中。所以你会做类似
的事情{{1}}
由于{{1}}的主要特征是删除其析构函数中包含的指针,我不确定在此处使用它是否有意义。据我了解,你应该在返回的指针上调用{{1}},而不是删除它。
答案 2 :(得分:1)
我想,必须有一种方法可以在一个声明中实现这一点。
我对此不太确定;关于临时值的观点实际上可能是需要一个声明来获得永久值。
此外,你正在搞乱智能指针的语义,你不应该这样做 - .get
在这里真的不应该使用。
Soooo,我要做的就是依赖于C ++作用域,并且不关心我先声明一个“普通”指针以便稍后制作智能指针的事实。
your_class::initialize_db() {
sqlite3 *sqlite;
int retval = sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite);
if(retval == SQLITE_OK)
m_db = std::unique_ptr<sqlite3>(sqlite);
}
答案 3 :(得分:1)
左值基本上可以出现在赋值运算符的左侧。所以错误说你只能检索可以分配给的东西的地址或函数。如果你有成员访问unique_ptr中的sqlite3 *指针,它会有用,但是你没有,并且有充分的理由。
更重要的是,在这种情况下你不应该使用智能指针。如果sqlite3_open需要一个sqlite3 **参数,则表示该函数将为sqlite3 *指针提供一个值。基本上它是C#或其他此类语言的out
参数。将它作为函数结果提供会更清楚,但结果代码会将其删除。这一切都很好,但智能指针想要控制这个值。您在初始化时设置一次值,但在此之后,智能指针会处理它。并且它需要这样做才能保持其约束:所有权的唯一性,当指针本身超出范围时的解除分配等。如果你基本上去覆盖内部的sqlite3 *指针,那么就不会发生因为智能指针无法拦截覆盖并解除分配它当前正在使用的对象。