获取指向智能指针指向的对象的指针-Ivalue错误

Getting the pointer to an object pointed towards by a smart pointer - Ivalue error

本文关键字:指针 -Ivalue 错误 对象 取指 获取 智能      更新时间:2023-10-16

我目前正在尝试调用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()操作的返回值只是一个临时表达式结果,因此在内存中没有一个可以从中获取地址的可识别位置。

我想,必须有一种方法在一句话中实现这一点。

有人能向我解释为什么这不起作用,以及我如何解决它吗?

&运算符只能与左值一起使用(或在向成员指针时与限定id一起使用)。表达式m_db.get()是一个右值,因为它按值而不是按引用返回指针,所以不能取其地址。

unique_ptr没有提供访问底层指针作为引用的方法,您需要像第一个示例中那样将副本存储在某个位置。

智能指针存储指针并在get时返回。这里要做的是相反的:您从sqlite3_open获得一个指针,并希望将其存储在智能指针中。所以你会做一些类似的事情

sqlite3* db = nullptr;
sqlite3_open(..., &db);
m_db.reset(db);

由于unique_ptr的主要功能是删除其析构函数中包含的指针,我不确定在这里使用它是否有意义。据我所知,你应该在返回的指针上调用sqlite3_close,而不是删除它

我想,必须有一种方法可以在一句话中实现这一点。

我对此不太确定;临时值的真正意义可能在于,需要一个语句才能获得一个永久值。

此外,您还扰乱了智能指针的语义,这是不应该做的——这里真的不应该使用.get

Sooo,我要做的是在这里依赖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);
}

左值基本上是可以出现在赋值运算符左侧的东西。因此,错误表明您只能检索可以分配给某个对象或函数的地址。如果您有成员访问unique_ptr内的sqlite3*指针,那么它会起作用,但您没有,这是有充分理由的。

更重要的是,在这种情况下不应该使用智能指针。如果sqlite3_open需要sqlite3**参数,那么这意味着该函数将为sqlite3*指针提供一个值。基本上它是一个out参数形式的C#或其他这样的语言。如果将其作为函数结果提供,则会更清楚,但结果代码却取消了这一点。这一切都很好,但智能指针希望控制这个值。你在初始化时设置了一次值,但在那之后,智能指针会处理它。它需要这样做来维护它的约束:所有权的唯一性,指针本身超出范围时的释放等。如果你基本上去覆盖里面的sqlite3*指针,那么这种情况就不会再发生了,因为智能指针无法拦截覆盖并释放它当前使用的对象。