2010-07-27 106 views
1

我正在用SQLite编写一个C++测试应用程序,为此我制作了一个小包装器。SQLite在完成语句时发生奇怪的崩溃

我不断地读取一些数据,第四次,当它完成声明时,它崩溃。我确定我将每个准备好的陈述与finalize匹配起来。第四次,在崩溃之前,数据已经成功读取。

一个好奇的事情是:我现在正在显示返回的语句指针(通过printf(“%p”)),并且在第一次读取时它总是0048D228。崩溃的是66676767.

我重新运行该程序,地址再次相同。

这里是我的课的重要组成部分:

class SQLiteResultSet 
{ 
private: 
    sqlite3_stmt *stmt; 
public: 
    inline SQLiteResultSet(sqlite3_stmt *pStmt) : stmt(pStmt) {} 
    inline bool next() { return sqlite3_step(stmt) == SQLITE_ROW; } 
    inline const unsigned char *textColumn(int colNum) { 
     return sqlite3_column_text(stmt, colNum); 
    } 
    inline const int intColumn(int colNum) { 
     return sqlite3_column_int(stmt, colNum); 
    } 
    inline void close() { 
     if(isOpen()) { 
      printf("----closing %p\n",stmt); 
      sqlite3_finalize(stmt); 
      printf("----closed\n"); 
      stmt = NULL; 
     } 
    } 
    inline bool isOpen() { return stmt != NULL; } 
    inline ~SQLiteResultSet() { close(); } 
}; 

class SQLiteGateway 
{ 
private: 
    sqlite3 *db; 
    SQLiteResultSet *rs; 

    void resetResultSet(); 

public: 
    SQLiteGateway(char *dbName); 
    SQLiteResultSet *select(char *query); 
    bool tableExists(char *tableName); 
    void execute(char *query); 
public: 
    ~SQLiteGateway(void); 
}; 

SQLiteGateway::SQLiteGateway(char *dbName) 
{ 
    db = NULL; 
    rs = NULL; 
    int error = sqlite3_open(dbName, &db); 
    if (error) 
    { 
     throw sqlite3_errmsg(db); 
    } 
} 

void SQLiteGateway::resetResultSet() 
{ 
    if(rs != NULL) 
    { 
     delete rs; 
     rs = NULL; 
    } 
} 

SQLiteResultSet *SQLiteGateway::select(char *query) 
{ 
    sqlite3_stmt *res; 
    const char  *tail; 

    resetResultSet(); 

    int error = sqlite3_prepare_v2(db,query,-1,&res,&tail); 
    if (error != SQLITE_OK || res == NULL) 
    { 
     throw sqlite3_errmsg(db); 
    } 

    rs = new SQLiteResultSet(res); 
    return rs; 
} 

SQLiteGateway::~SQLiteGateway(void) 
{ 
    resetResultSet(); 

    if(db != NULL) 
    { 
     sqlite3_close (db); 
    } 
} 

编辑:测试程序!

该查询应该返回至少1行(我放弃其余),并将一个整数作为第一列。在我的机器中,第三次迭代崩溃。

注意:从SQLiteGateway的声明中删除tableExists()和execute(),我没有在这里复制它们的实体,也没有在这个测试中使用它们。

int main() 
{ 
    SQLiteGateway *sqlg = NULL; 
    try 
    { 
     sqlg = new SQLiteGateway("./apptest.db"); 

     for(int i=0; i<5; i++) 
     { 
      SQLiteResultSet *rs = sqlg->select("select x from mytable"); 
      if(rs->next()) printf("%d\n", rs->intColumn(0)); 
      delete rs; 
     } 
    } 
    catch(char *str) 
    { 
     printf("Abnormal termination: %s\n", str); 
    } 
    if(sqlg != NULL) 
    { 
     delete sqlg; 
    } 
} 

这里是我与测试得到输出(0是读的价值,它不是在第3次迭代显示 - 关闭/关闭线前/后敲定)。

0 
----closing 0048D1E0 
----closed 
0 
----closing 0048D1E0 
----closed 
----closing 0048DFF8 

我仍然一无所知,但我发现,在本次测试中,如果我取代由它做什么直列使用SQLiteGateway的,没有崩溃!地址总是一样的。

+0

你可以发布测试计划吗?理想情况下,只需一个最小的'main'函数即可调用SQLite函数导致崩溃。 – jalf 2010-07-27 13:22:12

+0

我可以,当我今晚回到家时......至少从现在开始8个小时:(感谢 – 2010-07-27 13:38:29

+0

顺便说一下,在你的博客中有关RAII的很好的文章!我的SQLiteResultSet类不会初始化它的资源,但会获得它的所有权, SQLiteGateway忘记了它 – 2010-07-27 15:13:52

回答

0

我发现了这个错误:这是我如何管理SQLiteResultSet对象的生命期!

SQLiteGateway持有生成的最后结果集的引用,如果它不为空,则在下一个查询之前将其删除。但是,我可能已经在其他地方删除了它,这实际上就是我正在做的!结果集对象不再存在,但SQLiteGateway对象不知道,它仍然有一个非空指针。

我得重新设计解决方案。

我没有与指针工作多年,它显示!感谢您的关注!

编辑:容易解决。我只是放弃了这个参考。调用SQLiteGateway :: select()的人拥有生成的SQLiteResultSet对象并负责删除它。