Почему указатель this меняет свое значение при выполнении кода?

Я отлаживаю сбой, и я заметил, что на шаге через отладчик указатель this меняет свое значение и после 3 шагов, наконец, получает значение 0x00000001, и приложение вылетает.

Теперь значение 0x00000001, очевидно, неверно, но действительно ли я должен ожидать, что значение this изменится, когда я пройду через отладчик?

Ниже приведен конструктор, который я отлаживаю, где он падает. Я включил значение указателя this в комментарии к каждому шагу, и, как вы можете видеть, оно немного прыгает.

CADOCommand::CADOCommand(CADODatabase* pAdoDatabase, CString strCommandText, int nCommandType)
{
    m_pCommand = NULL;
    m_pCommand.CreateInstance(__uuidof(Command)); // this = 0x515f9d10
    m_strCommandText = strCommandText; // this = 0x2c0c0ee8
    m_pCommand->CommandText = m_strCommandText.AllocSysString(); // this = 0x515f9d20
    m_nCommandType = nCommandType; // this = 0x70847a55
    m_pCommand->CommandType = (CommandTypeEnum)m_nCommandType; // this = 0x00000001
    m_pCommand->ActiveConnection = pAdoDatabase->GetActiveConnection(); 
    m_nRecordsAffected = 0;
}

Существуют ли какие-либо обстоятельства, при которых значение this может или должно измениться по мере выполнения кода в данной функции-члене?

Обновить

Я должен добавить для записи и в ответ на несколько комментариев, я отлаживал выпускную сборку, но когда я отлаживал ту же функцию в отладочной сборке, значение this в конце концов не изменилось.

Так что же это значит, проблема только в релизной сборке?

Комментарий @drescherjm получил одобрение, в котором говорится in release mode the this pointer is not correct because of optimization, но что именно это означает под «неправильным»? Что мы не можем доверять указателю this в сборке релиза (это подделка) или что значение указателя правильное, но сборка релиза не работает из-за оптимизации?


person zar    schedule 23.08.2016    source источник
comment
Внутри области действия функции-члена this никогда не должно изменять значение. Кажется, кто-то может переполнить буфер в CreateInstance и AllocSysString   -  person StoryTeller - Unslander Monica    schedule 23.08.2016
comment
Скорее всего, это ошибка в вашем коде, где вы используете неверный указатель для доступа к данным. Поскольку в вашем случае this кажется, что он находится в стеке, неправильное использование указателя (т.е. выполнение доступа за пределами границ) изменяет его. Кстати, а что такое m_pCommand? Какой-нибудь умный (или тупой) указатель?   -  person SergeyA    schedule 23.08.2016
comment
Если только вы не перезапишете его значение, что и происходит здесь. Посмотрите на строку 1: m_pCommand = NULL;   -  person unexpectedvalue    schedule 23.08.2016
comment
При отладке добавьте точку останова записи в память по адресу &this. Он должен быстро поймать преступника.   -  person StoryTeller - Unslander Monica    schedule 23.08.2016
comment
Скорее всего, у вас есть переполнение буфера или висячий указатель где-нибудь (где угодно) в вашей программе. Используйте valgrind, чтобы узнать.   -  person n. 1.8e9-where's-my-share m.    schedule 23.08.2016
comment
Пока определение m_pCommand не предоставлено, вопрос является оффтопом и должен быть закрыт.   -  person SergeyA    schedule 23.08.2016
comment
Это отладочная сборка. Я имею в виду, что в режиме выпуска указатель this неверен из-за оптимизации.   -  person drescherjm    schedule 23.08.2016
comment
@SergeyA m_pCommand кажется COM-объектом типа _CommandPtr, и даже я не могу найти его определение в своем решении.   -  person zar    schedule 23.08.2016
comment
@drescherjm его релизная сборка.   -  person zar    schedule 23.08.2016
comment
@zar любая отладка, выполненная в программе с включенной оптимизацией, будет давать приблизительное представление о том, что происходит за кулисами - после оптимизации не обязательно будет сопоставление 1: 1 того, что вы написали, с тем, что выполняется . Если вообще возможно выследить проблему в режиме отладки, я обычно пробую это в первую очередь из-за предположений, связанных с выяснением того, что происходит в выпускной сборке.   -  person jaggedSpire    schedule 23.08.2016
comment
Отладка оптимизированного кода трудна. Вы не можете полностью доверять отладчику, и код больше не соответствует исходному коду. В таких случаях я лично считаю полезным взглянуть на сгенерированный asm, чтобы выяснить, что на самом деле происходит.   -  person Jesper Juhl    schedule 23.08.2016
comment
@jaggedSpire понимается, в частности, для локальных переменных или переменных-членов, но влияет ли это также на указатель this?   -  person zar    schedule 23.08.2016


Ответы (2)


В зависимости от отладчика может быть нормальным видеть изменение значения this между нажатием функции и входом в нее.

this==0xcccccccc перед входом в функцию

нажатие S::f()

это правильный адрес после входа в функцию

ввод S::f()

Однако после входа в функцию значение this не должно измениться1. Если это так, это, вероятно, означает, что у вас переполнение буфера и перезапись стека.

Выяснить проблему может быть непросто. Вы можете попробовать поставить точки останова памяти на this, чтобы увидеть, когда он изменится, или закомментировать код, пока проблема не исчезнет. Это должно помочь вам сузить его. Обратите внимание, что виновником может быть даже не эта конкретная функция: повреждение памяти печально известно тем, что вызывает хаос в несвязанных местах.

Вы также, кажется, смотрите на это, используя оптимизированную сборку. Будьте очень осторожны и не полагайтесь на отладчик при использовании оптимизаций: переменные могут исчезнуть из вашего кода, и у вас создастся впечатление, что их значение неверно. Если вы можете воспроизвести проблему, я бы попробовал зарегистрировать this где-нибудь вместо того, чтобы смотреть на нее через отладчик. Все это на самом деле может быть отвлекающим маневром.

1Однако this может измениться, когда вы вызываете другую функцию-член в иерархии, особенно когда задействованы виртуальные базы.

person isanae    schedule 23.08.2016
comment
Я добавил обновление к своему вопросу, и теперь эта проблема связана с отладкой и сборкой выпуска. Понятно, что переменные могут исчезнуть в сборке релиза из-за оптимизации, но указатель this не может исчезнуть, но его значению все равно нельзя доверять? И мы просто игнорируем это, когда, скажем, падает только релизная версия? - person zar; 25.08.2016
comment
@zar Указатель this может абсолютно исчезнуть, если в этом нет необходимости. То, что вы (или отладчик) считаете указателем this, на самом деле может использоваться для чего-то другого внутри этой функции. - person isanae; 25.08.2016
comment
Спасибо, и все же это открывает гораздо больше вопросов. WinDbg — это низкоуровневый отладчик и множество операций, связанных с проверкой того или иного адреса памяти, просмотром отпечатка объекта в памяти, указателем стека и т. д., и теперь мы знаем, что не можем доверять указателям в релизной сборке, где мы и наблюдаем сбой :) - person zar; 25.08.2016
comment
@zar Дело не в том, что указателям нельзя доверять. Вы не можете полагаться на то, что существует какая-либо связь между вашим исходным кодом и сгенерированным кодом. Отладчики полезны в неоптимизированных сборках, потому что существует (в основном) перевод исходного кода в машинный код один к одному. Однако они могут вводить в заблуждение, когда код оптимизирован, потому что они делают предположения, которые уже могут не соответствовать действительности. Проблема не в кодегене, а в отладчиках. - person isanae; 25.08.2016
comment
@zar Я предлагаю вам задать новый вопрос о причинах, по которым вы не можете легко отлаживать оптимизированный код. Кажется, их нет. - person isanae; 25.08.2016

Поскольку ваш пример начинается с создания экземпляра из GUID, полученного с помощью __uuidof, есть один фактор, который также может способствовать тому, что выпуск сильно отличается от кода отладки: согласно документации, __uuidof восстанавливается во время выполнения в отладочных сборках и компилируется для релизных сборок. В первом случае в худшем случае может быть затронут порядок загрузки/привязки модуля.

__uuidоператора

https://msdn.microsoft.com/en-us/library/zaah6a61.aspx


Примечание:

В отладочной сборке __uuidof всегда инициализирует объект динамически (во время выполнения). В релизной сборке __uuidof может статически (во время компиляции) инициализировать объект.

Когда что-то пойдет не так с управлением версиями или иным образом, также возможно, что значение времени выполнения будет отличаться от результата со статической привязкой, что означает, что вы можете отлаживать разные объекты в сценариях выпуска и отладки.

person Glenn Slayden    schedule 26.03.2017
comment
Вы собирались опубликовать этот ответ здесь? Это не имеет никакого отношения к вопросу. - person isanae; 27.03.2017
comment
@isanae Я дал некоторые объяснения. Если вы все еще считаете, что это не имеет значения, дайте мне знать, и я откажусь. - person Glenn Slayden; 27.03.2017
comment
Хотя в примере действительно используется __uuidof, я не думаю, что это вообще имеет отношение к вопросу, который касался изменения значения this внутри ctor. Впрочем, мне все равно. - person isanae; 27.03.2017