2016-12-29 11 views
1

Рассмотрим следующий фрагмент кода:Это ошибка в MSVC 2010 или я что-то не так?

В database_sqlite.h:

class __declspec(dllexport) SQLiteDatabase : public Database 
{ 
    virtual void GetTableProperties(DatabaseTable *table, std::vector<std::wstring> &errorMsg); 
protected: 
    struct SQLiteImpl; 
}; 

struct SQLiteDatabase::SQLiteImpl 
{ 
    std::wstring m_catalog; 
    std::wstring_convert<std::codecvt_utf8<wchar_t> > m_myconv; 
}; 

В database_sqlite.cpp:

void SQLiteDatabase::GetTableProperties(DatabaseTable *table, std::vector<std::wstring> &errorMsg) 
{ 
    sqlite3_stmt *stmt = NULL; 
    std::wstring errorMessage; 
    int result; 
    std::wstring query = L"SELECT * FROM \"sys.abcattbl\" WHERE \"abt_tnam\" = ? AND \"abt_ownr\" = ?;"; 
    const unsigned char *dataFontName, *headingFontName, *labelFontName; 
    int res = sqlite3_prepare_v2(m_db, sqlite_pimpl->m_myconv.to_bytes(query.c_str()).c_str(), (int) query.length(), &stmt, 0); 
    if(res == SQLITE_OK) 
    { 
const char *name = sqlite_pimpl->m_myconv.to_bytes(table->GetTableName().c_str()).c_str(); // I used this line for debugging purposes 
    res = sqlite3_bind_text(stmt, 1, sqlite_pimpl->m_myconv.to_bytes(table->GetTableName().c_str()).c_str(), -1, SQLITE_STATIC); 
    if(res == SQLITE_OK) 
    { 
     res = sqlite3_bind_text(stmt, 2, sqlite_pimpl->m_myconv.to_bytes(table->GetSchemaName().c_str()).c_str(), -1, SQLITE_STATIC); 
     if(res == SQLITE_OK) 
     { 
      while(true) 
      { 

символ * result_query = sqlite3_expanded_sql (STMT); res = sqlite3_step (stmt);

Здесь * result_query содержит = "SELECT * FROM" sys.abcattbl "WHERE" abt_tnam "= '' AND" abt_ownr "= '';" Я использую MSVC2010, и, к моему удивлению, «* name» содержит пустую строку. Первый вызов «to_bytes()» преуспел, так как я могу проверить запрос, который будет использоваться.

Должен ли я что-то сделать после первого вызова «to_bytes()»? Или мне просто нужно обновить компилятор?

ответ

0

Нет, вы делаете что-то неправильно.

На самом деле, сейчас нет to_bytes, но предположим, что это тип базы на std::basic_string, поэтому std::string и семья.

to_bytes возвращает временный объект этому экземпляру строки, поэтому, когда вы вызываете c_str(), вы получаете указатель на первый символ строки, который больше не будет существовать после завершения инструкций. У вас в основном есть неопределенное поведение, из-за того, что name является обвисшим указателем, и вы пытаетесь его вывести.

Вам нужно будет выделить память и скопировать туда строку или просто использовать std::string, где типы проблем не возникают.

Причина, по которой ваш вызов sqlite3_prepare_v2 преуспевает, заключается в том, что строка, возвращаемая to_bytes, все еще существует. Строка уничтожается, когда оператор заканчивается, поэтому, когда res присваивается возвращаемое значение sqlite3_prepare_v2. Не раньше, и, следовательно, вызов преуспевает, поскольку действительный указатель на строку передается.

И, тем не менее, обновите свой компилятор.

+0

, но затем, как получилось, вызов «sqlite3_prepare_v2()» преуспел? Также, пожалуйста, проверьте мое редактирование - я добавляю больше кода. Спасибо. – Igor

+0

@Igor см. Мое редактирование, пожалуйста. – Rakete1111

+1

все работает сейчас. Исправлена ​​проблема с заменой последнего параметра sqlite3_bind_text() на "SQLITE_TRANSIENT". По какой-то причине я был уверен, что мне нужен SQLITE_STATIC. Thx снова и с Новым годом. – Igor