指针更改地址

时间:2018-03-18 17:53:52

标签: c++ pointers sqlite

我一直在创建一个与本地SQLite数据库交互的C ++桌面应用程序。我使用存储库模式并将从数据库中检索到的数据存储在类的实例中(用作数据模型)。我在我的应用程序的其他地方实现了这种模式,一切正常。但是,似乎在这个特定的实现中,类实例(数据模型)的地址似乎在构造和销毁之间发生了变化。

以下是使用我在调试执行期间记录的内存地址设置代码的示例...

存储库类 - 构造函数:

目前,我正在使用此存储库类来维护对Configs数据模型类的控制。这可能会在将来发生变化,但我目前的想法是为了便于构建和破坏这个对象(或者我认为!)。

ConfigsRepo::ConfigsRepo()
{
    this->_configs = new Models::Configs(); // Memory address: 0x039089e8
}

存储库类 - 获取方法:

我遗漏了数据库连接和SQL语句字符串,因为它们有效并且不是问题的一部分。

Models::Configs& ConfigsRepo::Get()
{
    int rc = sqlite3_exec("..", "..", &Sql::Convert, &this->_configs, NULL);

    // Check rc == SQLITE_OK, blah blah...

    return *this->_configs;  // Memory address: 0x03908901
}

Sql :: Convert方法:

数据库表中当前只有一行和一列。数据检索正常。

int Sql::Convert(void* ret, int count, char** data, char** columns)
{
    // "ret" is a reference to the "Configs" class instance passed
    // by the repository.

    // Memory address of "ret": 0x03918930 - most likely different
    // due to passing by reference.

    // Converting retrieved data to a bool and assigning to a
    // property of the referenced "Configs" class.
    // (if cell equals 1 then 'true', else 'false')
    (*(Models::Configs*)ret).SomeProp = atoi(data[0]) == 1;

    return 0;
}

存储库类 - 析构函数:

ConfigsRepo::~ConfigsRepo()
{
    delete this->_configs; // Memory address: 0x03908901 - exception thrown
    this->_configs = NULL;
}

正如您所看到的," Configs"的内存地址。对象在Sql::Convert回调方法后发生更改。在破坏ConfigsRepo类(我尝试delete this->_configs时)时,会抛出异常:Invalid address specified to RtlValidateHeap

我不确定为什么内存地址似乎发生了变化,我无法看到这个问题。

注意:我已经开始相信以这种方式调用delete并不是关于设计模式的好习惯,我将在以后重构我的代码。我现在只需要它。 :)

提前致谢!

1 个答案:

答案 0 :(得分:1)

查看sqlite3_exe(...)上的sqlite3文档:

  

sqlite3_exec()的第四个参数被转发到每个回调调用的第一个参数。

所以,关于你的功能:

int rc = sqlite3_exec("..", "..", &Sql::Convert, &this->_configs, NULL);

你实际上是在传递一个指针指针,即this-> configs的地址,它本身就是Models::Configs的指针

在回调网站上,您将其视为:

(*(Models::Configs*)ret).SomeProp = atoi(data[0]) == 1;

这是一种令人费解的说法:

(Models::Configs*)ret->SomeProp = atoi(data[0]) == 1;

你可以看到,你没有撤消你在呼叫站点所做的事情。

所以,我建议你改变你的sqlite3_exec()

int rc = sqlite3_exec("..", "..", &Sql::Convert, this->_configs, NULL);
                                                 ^^^^^^^^^^^^^^

除此之外:您无需将Sql::Convert作为&Sql::Convert传递,就像Sql::Convert

一样