#c #unicode #c builder #access-violation #c builder-10.3-rio
Вопрос:
Мне нужно некоторое теоретическое объяснение следующего нарушения доступа к памяти, прежде чем даже вводить метод:
String testMethod (AnsiString param1);
AnsiString A1 = testMethod(A1);
Я пытаюсь понять теорию, лежащую в основе проблемы.
A1
инициализируется возвращаемым значением testMethod()
while в то же время, в которое оно передается testMethod()
. Что происходит до фактического ввода метода? При передаче в testMethod()
него не имеет фактического значения/случайного значения, не так ли? Создается локальная копия A1
, действительно ли во время этого процесса возникает исключение?
При попытке отладки вводится множество AnsiString
, UnicodeString
, и AnsiStringBase
методов.
Почему это работает, когда я изменяю сигнатуру метода таким образом:
AnsiString testMethod (AnsiString param1);
Комментарии:
1. Что такое
AnsiString
иString
? Классы, типы или что-то еще? Здесь может происходить несколько вещей, но точная проблема зависит от конкретных типов.2. @1201ProgramAlarm
AnsiString
иUnicodeString
являются строковыми классами в RTL C Builder.String
это просто определение типа дляUnicodeString
.3. Если компилятор может обнаружить , что код является бессмыслицей (т. Е. Проверяет
this
nullptr
, является ли он или передает неинициализированную переменную функции и возвращает ее), компилятор может делать с кодом все, что угодно. См. правило «как если бы».4. Это тоже хорошая информация, спасибо @PaulMcKenzie.
Ответ №1:
AnsiString A1 = testMethod(A1);
Когда вы достигнете этой точки:
AnsiString A1
это имя A1
существует и известно компилятору. Таким образом, вы можете использовать его дальше вправо. Однако вы вызываете testMethod
с необработанным блоком памяти, который еще не был создан. Это взорвется, когда он попадет в конструктор копирования, который попытается прочитать элементы внутри A1
.
Вот уточнение: хотя все это написано в одной строке, у вас есть несколько шагов, и все решается в разное время.
Во время компиляции выделяется группа байтов и метка A1
, используемая для ссылки на них.
Во время выполнения выполняется инструкция для инициализации A1
. Это работает путем вызова конструктора, который предназначен для ожидания необработанной памяти и отвечает за превращение этой памяти в легальный экземпляр этого типа.
Однако в этом случае для получения значения, используемого для инициализации этой переменной, используется вызов функции, который передается A1
в качестве параметра. Но A1
еще не был инициализирован.
На другом уровне детализации код реализуется следующим образом: функция, возвращающая тип класса, реализуется путем передачи адреса области результатов в качестве другого аргумента. Определение A1
заставило компилятор выделить для этого память, но с этим еще ничего не было сделано. На этом этапе выполнения он вызывает функцию __impl_testMethod(amp;A1, copy_of(A1));
.
При попытке отладки вводится множество методов AnsiString, UnicodeString и AnsiStringBase.
Вы видите конструктор копирования в действии. Вы, вероятно, действительно хотели определить это как:
String testFunction (const AnsiStringamp; param1);
потому что нет причин дублировать объект в param1
том случае, если эта функция будет просматривать его, но не изменять свою собственную частную копию.
И в C нет «методов», а скорее функций-членов, и в любом случае это даже не функция-член (насколько я могу видеть в вашей операции). Это правильно описывается как «свободная функция».
Комментарии:
1. Это тот ответ, на который я надеялся, но не ожидал получить, большое спасибо. Тем не менее, есть один момент, который я хотел бы прояснить: разве конструктор копирования не вызывается для создания локальной копии A1 для метода (copy_of(A1)) и не завершается в этом месте, вместо того, чтобы конструктор копирования устанавливал A1 в значение функции-члена? Функция еще не введена, так что она должна быть локальной копией, верно? И с amp;A1 вы, вероятно, имели в виду какую-то другую переменную, зарезервированную для хранения адреса возвращаемого значения, я думаю.
2.Передача
A1
по значению вtestMethod()
будет пытаться создать копиюA1
во временный объект, таким образом, вызываяAnsiString
конструктор копирования сA1
исходным объектом для копирования,testMethod()
который затем вводится. НоA1
еще не является допустимым объектом, поэтому создание этой временной копии является неопределенным поведением. Ваш сбой, скорее всего, связан с созданием этого временного, но это также может быть при использованииparam1
для любых целей внутри функции (возможно, присвоение возвращаемого значения?). Только отладчик может точно сказать вам, где на самом деле происходит сбой.3. Отлично, спасибо, Реми, это последняя информация, которую я упустил. Таким образом, это произошло из-за первого случая, потому что во время отладки я смог увидеть, что метод еще не был введен.
4. Под
copy_of_(A1)
этим я подразумеваю, что он вызовет конструктор копирования на A1, и именно полученная копия будет переданаtestMethod
. РезультатtestMethod
создается непосредственно в именованную памятьA1
, описанную в стандарте таким образом, как в C 17, и что на самом деле происходит после оптимизации в более ранних компиляторах.5. @kvirk вы пробовали использовать Проводник компилятора ?
Ответ №2:
AnsiString A1 = testMethod(A1);
это просто неопределенное поведение, независимо testMethod()
от того, возвращает String
или AnsiString
. Нет никаких причин, почему он падает в одну сторону, но не в другую. Просто не делай этого, и точка! Вы пытаетесь передать копию A1
testMethod()
до A1
того, как она была создана.
Комментарии:
1. Спасибо, я знаю, что это не тот путь, но это произошло из-за какого-то действия по замене строки, и я из тех людей, которые пытаются понять, почему что-то происходит, и мне просто недостаточно отложить это в сторону в записи UB. Подобные вещи-хороший шанс понять внутреннюю работу, по крайней мере, я стараюсь.
2. Опять же, не пытайтесь понять, что делает компилятор при вызове неопределенного поведения , он может буквально делать все, что захочет. Вы не можете полагаться на результат UB, и этот код абсолютно UB, простой и понятный.
3. Понял, так что не нужно ломать голову над причиной, почему это сработало с возвращаемым значением AnsiString.