2014-01-16 2 views
6

Я прочитал много сообщений на форуме о указателях, Assigned function, Free function, function, function, etc ... Я уже знаю Свободная функция не удаляет ссылку указателя на назначенный объект и FreeAndNil делает это ... Все сообщения I читать лечить эту тему, учитывая, что метод Create уже выполнен, или, другими словами, с учетом уже созданного объекта.Почему Assigned возвращает true для неинициализированных переменных?

Мой вопрос: Почему функция Assigned возвращает true для неинициализированной переменной объекта?

Выполните пример:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Qry: TADOQuery;  
begin 
    if Assigned(Qry) then 
    ShowMessage('Assigned') 
    else 
    ShowMessage('Unassigned'); 

    Qry := TADOQuery.Create(nil); 

    if Assigned(Qry) then 
    ShowMessage('Assigned') 
    else 
    ShowMessage('Unassigned'); 
end; 

Этот пример показывает 'Назначено' дважды!

Заключение: сразу после того, как Qry был объявлен, и до того, как его метод создания был выполнен, указатель на Qry не является NIL!

Если я положил Qry := nil; на первую строку в процедуру выше, все работает отлично ... оно отображает «Неназначенные» и «Назначено».

Почему?

Есть ли какой-либо безопасный способ узнать, имеет ли переменная класса уже выполненный метод создания?

+4

посмотрите на это: http://stackoverflow.com/questions/132725/are-delphi-variables-initialized-with-a-value-by-default – idursun

+1

«переменная класса уже выполнил его создать метод «переменные не имеют никаких методов! 'var o: TObject; i: целое число; s: строки; i: = TStringList.Create.Count; s: = TStringList.UnitName; o: = TStringList.Create; '- каждый из трех операторов имеет одну и ту же структуру: существует какое-либо любое выражение, которое вычисляет какое-либо значение; и существует переменная, в которой сохраняется значение (но не выражение, оно больше не существует в этой точке). Когда выполняется выражение (с этими «методами»), еще нет var. Когда приходит вар, чтобы играть - больше нет выражения –

ответ

3

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

+2

Я понятия не имею, почему вы были проголосовали за это (дважды). –

+0

Похоже, у некоторых людей есть проблемы с вопросами в ответах? (Даже реторические вопросы ...) – Rodrigo

7

Ваша переменная является локальной переменной и поэтому не инициализирована. Он может содержать любое значение.

The documentation говорит:

На платформе Win32, содержимое локальная переменная не определена, пока значение не присваивается им.

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

Вы спрашиваете:

Есть ли безопасный способ узнать, является ли переменная класса уже есть свой метод создания казнят?

Если эта переменная является локальной переменной, ответ отрицательный. Ответственность перед вами - программист. На практике это редко возникает из-за того, что хороший код имеет короткие процедуры, что затрудняет вам ускорение. И даже если вы сделаете компилятор, вы всегда будете предупреждать вас.

Инициализируются другие типы переменных, такие как поля классов и глобальные переменные.

+0

Я думаю, что Delphi/LLVM инициализирует указатели на классы, так как они похожи на указатели на интерфейсы. Интересно, есть ли много сообщений об ошибках, например «мое приложение отлично работает в iPad, но переменные не проверяют nil на симуляторе iOS» ;-) –

4

Из документации Assigned функции (курсив мой):

Использование Assigned для определения указателя или процедура ссылается на P, является ли ноль. P должен быть переменной ссылкой указателя или процедурного типа. Назначение (P) соответствует тесту P <> nil для переменной указателя, а @P <> nil для процедурной переменной.

Назначение возвращает false, если P равно нулю, в противном случае - true.

Примечание: Назначенный не может обнаружить оборванный указатель - то есть тот, который не равен нулю, но больше не указывает на действительные данные. Например, в примере кода для Assigned Assigned не обнаружит, что P недействителен.

Assigned функция эффективно реализована как:

function Assigned(const P): Boolean; 
begin 
    Result := Pointer(P) <> nil; 
end; 

Так что функция действительно не проверяя, действительно ли значение присваивается. Скорее, он проверяет побочный эффект от назначения.

  • В результате функция является гарантированно вернуть True если он назначен.
  • Но поведение не определено, если значение неинициализировано. В принципе, поскольку неинициализированное значение имеет значение мусора, оставшееся от предыдущих операций, оно должно быть может быть ноль, или если не может.

Следует отметить, что Assigned не имеет возможности определить срок действия его стоимости. Например. Следующий вызов Assigned возвращает True, хотя основной объект больше недействителен.

var 
    LObject: TObject; 
begin 
    LObject := TObject.Create; 
    LObject.Free; 
    if Assigned(LObject) then ShowMessage('Still assigned!?'); 
end; 

EDIT: Добавление

В ответ на вторую часть вашего вопроса.

Есть ли какой-либо безопасный способ узнать, имеет ли класс переменную уже выполненный метод создания?

Нет надежного способа определить, был ли экземпляр объекта создан. (Также нет способа достоверно подтвердить, что он еще не был уничтожен.)

Однако существуют соглашения (и передовые методы), которые вы можете выполнить, чтобы помочь вам в этом.

Прежде всего обратите внимание, что вы должны быть «неуверены», если что-то было создано, если это преднамеренная функция этого фрагмента кода. Например. Если вы хотите, чтобы объект был «ленивым инициализированным».

  • То, что я пытаюсь сказать здесь: Никогда проверка Assigned только потому, что вы беспокоитесь, что там может быть ошибка, что не мешает ему быть назначены.
  • Не только это невозможно сделать надежно, но вы перекомпилируете свой код ... Какой увеличивает вероятность ошибок.
  • Также, если вы обнаружите, что что-то неожиданно не назначено, то что вы можете с этим сделать? Игнорировать это было бы просто бессмысленно. Кроме того, это нехорошо сказать: «Хорошо, тогда я создам объект». Потому что тогда вы дублируете логику создания в нескольких местах.
  • В принципе, вы должны попытаться сделать все части своей программы правильными - не пытайтесь ли вы дважды проверить себя повсюду.

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

  • При первой же возможности, обеспечить ссылочную переменную/поле инициализируется в ноль. Таким образом, гарантируется присвоение значения, которое означает, что объект не создан. (Да, именование немного искажено.)
  • Вы можете установить ссылку на vairable/field на новый экземпляр объекта или установить его, скопировав другую ссылку на уже существующий объект. (Обратите внимание на существующий Другой крупный также может быть ноль, но это не вызывает никаких проблем.)
  • Если вы когда-нибудь уничтожить объект (или даже просто хотите прекратить его использование с этой ссылки), установите переменную/полевые ссылки на nil еще раз.
  • ПРИМЕЧАНИЕ: Delphi уже инициализирует поля членов нового класса. Поэтому им не потребуется особого внимания.
Смежные вопросы