Сколько работы нужно выполнить в конструкторе? - PullRequest
50 голосов
/ 16 ноября 2008

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

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

Какое элегантное решение для этого?

Ответы [ 18 ]

1 голос
/ 19 ноября 2008

RAII является основой управления ресурсами C ++, поэтому приобретайте ресурсы, которые вам нужны, в конструкторе, освобождайте их в деструкторе.

Это когда вы устанавливаете классовые инварианты. Если это требует времени, это требует времени. Чем меньше у вас конструкций типа «если X существует, то есть Y», тем проще будет проектировать остальная часть класса. Позже, если профилирование покажет, что это проблема, подумайте об оптимизации, такой как ленивая инициализация (получение ресурсов, когда они вам нужны).

1 голос
/ 16 ноября 2008

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

1 голос
/ 16 ноября 2008

Убедитесь, что ctor не делает ничего, что могло бы вызвать исключение.

0 голосов
/ 21 декабря 2009

Отличный вопрос: пример, который вы привели, когда объект «Каталог» имеет ссылки на другие объекты «Каталог», также является хорошим примером.

Для этого конкретного случая я бы переместил код для создания подчиненных объектов из конструктора (или, возможно, сделал бы первый уровень [непосредственные дети], как рекомендует другой пост), и имел бы отдельную «инициализацию» или «сборку» механизм).

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

0 голосов
/ 21 декабря 2009

Я голосую за тонких конструкторов и добавляю дополнительное поведение "неинициализированного" состояния к вашему объекту в этом случае.

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

Может быть трудно отлавливать ошибки от таких объектов, если они становятся статическими, потому что конструктор затем запускается перед main () и отладчику труднее отследить.

0 голосов
/ 16 ноября 2008

Массивы объектов всегда будут использовать конструктор по умолчанию (без аргументов). Обойти это невозможно.

Существуют «специальные» конструкторы: конструктор копирования и оператор = ().

У вас может быть много конструкторов! Или попозже со множеством конструкторов. Время от времени Билл из Л-ла-Лэнд хочет нового конструктора с плавающей запятой, а не с двойными, чтобы спасти эти 4 паршивых байта. (Купите немного оперативной памяти Билл!)

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

Нельзя сделать виртуальную логику конструктора и изменить ее в подклассе. (Хотя, если вы вызываете метод initialize () из конструктора, а не вручную, виртуальные методы не будут работать.)

.

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

Поэтому я, как дизайнер, предпочитаю иметь минимальные конструкторы, которые (необязательно, в зависимости от их параметров и ситуации) вызывают метод initialize ().

В зависимости от обстоятельств initialize () может быть закрытым. Или он может быть общедоступным и поддерживать несколько вызовов (например, повторная инициализация).

.

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

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

0 голосов
/ 16 ноября 2008

Это действительно зависит от контекста, то есть проблемы, которую должен решить класс. Должен ли он, например, всегда быть в состоянии показать текущих детей внутри себя? Если ответ «да», то дочерние элементы не должны загружаться в конструктор. С другой стороны, если класс представляет собой снимок структуры каталогов, его можно загрузить в конструктор.

0 голосов
/ 16 ноября 2008

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

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