Ошибка при хранении указателей в векторах c ++ - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь использовать векторы c ++ для хранения указателей на структуру, подобную этой:

  struct SourceDir {
    int id;
    const unsigned char *alias;
    const unsigned char *description;
    const unsigned char *path;
  };

, но затем я не могу получить значение, которое кажется поврежденным

      std::vector<SourceDir*> source_dirs;
      while ((step = sqlite3_step(stmt)) != SQLITE_DONE) {
        if (step != SQLITE_ROW) {
          std::cerr << "[ERROR] internal error (SQLite error code" << step << ")\n";
          exit(1);
        }

        struct SourceDir *sourceDir = new SourceDir;
        sourceDir->id = sqlite3_column_int(stmt, 0);
        sourceDir->alias = sqlite3_column_text(stmt, 1);
        sourceDir->path = sqlite3_column_text(stmt, 2);
        sourceDir->description = sqlite3_column_text(stmt, 3);

        source_dirs.push_back(sourceDir);
      }

      for (std::vector<SourceDir*>::iterator it = source_dirs.begin() ; it != source_dirs.end() ; ++it) {
        SourceDir *s = *it;
        std::cerr << s->description << "\n";
      }

он дает случайные значения примерно так:

@O?V
@O?V

Я не понимаю, что я сделал не так

Ответы [ 2 ]

0 голосов
/ 10 апреля 2020

Указатели хороши, но содержимое памяти, на которую они указывают, вероятно, изменилось (например, здесь: https://sqlite.org/capi3ref.html#sqlite3_column_blob вы можете прочитать, что возвращенный указатель действителен только в течение некоторого времени).

В общем, избегайте использования сырых указателей в C ++. В этом случае вы можете просто использовать std :: string для копирования данных, предоставляемых sqlite.

Сравните этот код, который вносит несколько небольших изменений, чтобы избежать ручного управления памятью и необработанных указателей:

struct SourceDir
{
        int id;
        std::string alias;
        std::string description;
        std::string path;
};



std::vector<SourceDir> source_dirs;
while ((step = sqlite3_step(stmt)) != SQLITE_DONE) {
        if (step != SQLITE_ROW) {
                std::cerr << "[ERROR] internal error (SQLite error code" << step << ")\n";
                exit(1);
        }

        source_dirs.emplace_back();
        auto& sourceDir = source_dirs.back();
        sourceDir.id = sqlite3_column_int(stmt, 0);
        sourceDir.alias = sqlite3_column_text(stmt, 1);
        sourceDir.path = sqlite3_column_text(stmt, 2);
        sourceDir.description = sqlite3_column_text(stmt, 3);
}

for (const auto& s : source_dirs)
{
        std::cerr << s.description << "\n";
}
0 голосов
/ 10 апреля 2020

C строки имеют тип char* или const char*. Поскольку они настолько распространены и все еще важны, существует дополнительная перегрузка для оператора << в std::ostream. Эта конкретная перегрузка для char* печатает разыменованные символы, пока не найдет нулевой байт.

Однако unsigned char* - это другой тип, и будет использоваться другая перегрузка. Здесь просто указывается значение указателя. Это то, что вы видите.

Решение: Просто измените элементы строки на const char*.

Редактировать: Этот ответ просто неправильный. Та же перегрузка C String также выбрана для unsigned char*.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...