вторник, 20 января 2015 г.

Как несовершенны константные аргументы

Я тут попал в такие чудеса на виражах, что уже хотел застрелить компилятор и повеситься на шею кому-нибудь с жилеткой, чтобы рыдать аки дитя малое. Меня обидел компилятор! И причём не где-нибудь, а в Win32!!! Ну, посудите сами - он ссылки на строку посчитать не может, и втихаря вместо одной переменной, присваивает значения двум! Вот сейчас расскажу как.

Есть у меня процедура со строкой в аргументе. Она слегка чистит листбокс и потом по аргументу заливает в список новые элементы. Вызывается из разных мест. В том числе по клику на списке, где  в качестве аргумента в ту процедуру передаётся строковое свойство текущего элемента.

И что-то не совсем правильно работает. Я смотрю - после присвоения локальной переменной непустого значения аргумент процедуры вдруг - раз, и стал равным этому присвоению!  Да, вот константный аргумент вдруг взял и поменялся сам. Причем, если аргумент приходил пустой - то в него ничего не пишется после занесения нового значения в локальную переменную, всё такой же он пустой остаётся как и был.

Полазил я в CPU на предмет совпадения адресов - но это так, чисто посмотреть с укором в подкапотное пространство. А дай, думаю, присвою той локальной переменной значение аргумента. Присваивается, идёт дальше, и вот в момент "волшебного" присвоения - Бах! - неверная операция с указателем! И только тогда, когда аргумент не пуст.

Стал я думать-гадать-искать и понял, что переданная мной непустая строка принадлежит тому элементу списка, который убивается внутри процедуры перед присвоением нового значения локальной строке. А константные аргументы как передаются? - А в том числе и по ссылке! И видимо, поскольку я строковое свойство кладу в неизменном виде, как раз такой вариант развития событий и был выбран компилятором. И выходит, что в магический момент ссылка уже битая, и совпадает как-то хитрослучайно точно с адресом локальной переменной. 

Это просто счастливое совпадение, что мёртвая ссылка точно легла на локальную переменную! 

Лечение прошло банально - передачей параметра по значению. Но каково?! Как компилятор не отследил, что область памяти занята процедурой?! 

К сожалению, я не смог воспроизвести ситуацию на простом примере. И если кто-нибудь понял что за оптимизация такая у компилятора происходит, то пусть попробует создать пример в пробирке для quality.embarcadero.com. А я свой рассказ заканчиваю. Спасибо за внимание!