Нужно ли устанавливать длину динамического массива при инициализации? - PullRequest
3 голосов
/ 15 марта 2011
type Tmyclass = class(TObject)
  somearray: array of TSometype
  FBool: Boolean;
  Fint: Integer;
  Fstr: string;
  constructor Create;
  destructor Destroy; override;
end;

implementation

constructor Tmyclass.Create;
begin
  inherited;
  SetLength(somearray,0); //is this needed?
end;

destructor TmyClass.Destroy;
begin
  SetLength(somearray,0); //this IS needed!
  inherited;
end;

И какие типы инициализируются при создании? Например, что я объявил в классе. FBool гарантированно будет ложным? гарантируется, что FInt равен 0? Fstr гарантированно будет ''?

А как насчет местного? Только строки?

Я использую Delphi XE.

Ответы [ 5 ]

13 голосов
/ 15 марта 2011

Динамические массивы являются управляемыми типами и поэтому всегда инициализируются в nil, что эквивалентно SetLength(..., 0).Вам никогда не нужно этого делать.

Единственный раз, когда вы можете быть пойманным, это когда вы возвращаете динамический массив из процедуры как возвращаемое значение функции.Фактически возвращаемое значение функции - это просто неявный параметр var.

Рассмотрим следующий код:

function Foo: string;
begin
  Result := Result + 'X';
end;

var
  i: Integer;

begin
  for i := 1 to 5 do
    Writeln(Foo);
  Writeln(Foo);
  Writeln(Foo);
end;

Выход

X
XX
XXX
XXXX
XXXXX
X
X

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

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

13 голосов
/ 15 марта 2011

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

  • строки будут ''
  • целых чисел будет 0
  • Переменные с плавающей запятой будут 0
  • логическое значение будет ложным
  • указатели и ссылки на объекты будут равны нулю
  • динамические массивы будут содержать ноль элементов.

и так далее.

Для локальных переменных и всего, что связано со стеком, он будет содержать мусор, поэтому вы обязаны предоставить значимое значение перед использованием переменных.

Что-то вроде:

procedure Something;
var
  x: Integer;
begin
  ShowMessage(IntToStr(X));
end;

покажет случайное значение.

7 голосов
/ 15 марта 2011

Оба вызова SetLength излишни, поскольку динамические массивы инициализируются и завершаются.

Все поля в экземпляре класса инициализируются в их соответствующие нулевые значения, то есть 0, ноль, False, '' и т. Д.

Локальные переменные инициализируются (и завершаются) только в том случае, если они относятся к типу, управляемому в течение жизни, например к строке, динамическому массиву или интерфейсу.

4 голосов
/ 15 марта 2011

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

Вы также спрашивали о локальных переменных.Да, вам нужно их инициализировать.Все они, кроме переменных одного из управляемых типов:

  • AnsiString
  • UnicodeString
  • WideString
  • тип интерфейса
  • тип динамического массива
  • вариант

Список взят из ответа Барри Келли, на который Сертак указал в комментариях: Какие переменные инициализируются, когда в Delphi?

0 голосов
/ 15 марта 2011

Если вы заранее знаете, насколько большим будет массив, было бы неплохо распределить его как единое целое, так это позволит избежать слишком большого количества перераспределений позже, лучше используя память. Кроме того, очистка массива, когда он больше не используется, освобождает его память (но Delphi знает, как очистить его, когда он выходит из области видимости).

...