С++: странное поведение: изменение возвращаемого значения в операторе return

У меня очень странное поведение в моем приложении.

Я расскажу о своей ситуации, а затем объясню, что происходит не так.

Ситуация

У меня есть метод с такой сигнатурой:

const StructureDef *getStructure(const std::string &theme, int index);

И я называю это в этом фрагменте кода:

const StructureDef *sDef = 0;
do 
{
    sDef = ss->getStructure(theme, rand() % ss->availableStructureCount());
} while (!sDef);

Я использую эту структуру do-while, потому что возвращаемое значение метода getStructure может быть NULL, в зависимости от комбинации theme и index. Так что в основном, то, что он делает, задает случайные структуры, пока мы не получим действительный. (Если вы хотите узнать подробности, взгляните на скриншоты.)

Метод выполняет итерацию по std::vector<StructureDef> с помощью ::iterator. И для каждого StructureDef он проверяет, принадлежит ли эта структура этой теме. Если это так, добавьте счетчик и проверьте, совпадает ли он с запрошенным индексом. Вот так:

// inside the loop
if (i++ == index)

Если это произойдет, то возвращается StructureDef *:

return sDef;

Что происходит неправильно

Я использую XCode 4.4 для этого отладчика, чтобы увидеть шаг за шагом, что происходит, что в основном является gdb.

Сначала метод, который я объяснил, найти StructureDef *, который соответствует моим потребностям. Поэтому он возвращает этот указатель. Вот скриншот момента перед тем, как он вернется в отладчик:

Return point in the debugger

(строка после цикла for просто return 0;)

Здесь указатель sDef * указывает на 0x1d563270, где находится правильный экземпляр StructureDef.

Следующий снимок экрана - это то, что мы получаем в куске кода, где я назвал этот метод:

Caller gets wrong address

Как вы можете видеть, указатель sDef *, который получил возвращаемое значение метода, теперь указывает на 0x2fe03804. Это не то, что метод вернулся вообще! Я думаю, что это указатель указывает куда-то в стек, а не на кучу. (Это должна быть куча, так как класс std::vector хранит свои объекты в куче, правильно?).

Я еще не могу использовать Valgrind, так как я нахожусь в Mac OS X 10.8, который не поддерживается Valgrind.

Я полностью удивлен этим поведением. Я не понимаю, почему это происходит... Может быть, мой компилятор сломан, или он делает какую-то странную "оптимизацию"?

Спасибо заранее! Мартейн


Чтобы прояснить комментарий DeadMG:

Я использую разные темы:

iron
wood
ice

и т.д...

Мои идентификаторы выглядят следующим образом:

iron__downside_touch_and_go
iron__platform__700_65
iron__wall_bang
wood__platform__600_40

и т.д. Что я хочу сделать, это выбрать структуру с определенным индексом в одной теме. Так что не индексируйте совокупность структур всех тем вместе, а индекс подмножества одной темы. Взгляните на кусок кода еще раз:)


Обновление!!!

Я дал неверную информацию. Вектор имеет тип std::vector<StructureDef>!! Он хранит объекты. Не указатели!

Итак, что (я думаю), что я делаю с вызовом .operator->(), это то же самое, что: &(*it). И похоже, что он работает. Для меня это выглядело немного глупо, чтобы писать и * друг за другом.


@Ben Voigt:

Архитектура: enter image description here

Оптимизация: enter image description here

Ответ 1

Он выглядел как отладчик, который я использовал (LLDB, а не GDB, поскольку я, хотя и первый) не отображал значения памяти правильно. После переключения на GDB отладчик показал адреса памяти, которые я видел, чтобы видеть. Когда я добавил выражение печати следующим образом:

printf("StructureDef* pointer = %llx\n", (unsigned long long int)(void*) sDef);

похоже, что GDB прав. В целях тестирования я переключился на LLDB, и, как ни странно, он работал правильно.

Возможно, я имею дело с тем, что написал этот парень: fooobar.com/questions/143101/...

Я надеюсь, что это ошибка в отладчике LLDB. Потому что, в противном случае, я думаю, что что-то действительно сломалось в моей установке.

Ответ 2

Измените вектор от std::vector<StructureDef> до std::vector<StructureDef*>. Когда вы заполняете вектор его составляющими указателями на StructureDef, динамически выделяйте память для каждого из кучи.