Каковы недостатки предварительной декларации? - PullRequest
3 голосов
/ 27 февраля 2012

Мне интересно, есть ли какой-либо недостаток для использования предварительных объявлений во всех местах, когда это возможно.Это если мой заголовок содержит только объявления.

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

Пример:

ах:

Class A
{
};

чч:

// Should I use and include "a.h" in the cpp file (e.g., a.cpp)
Class A;
Class B
{
    doSomething(A *a);
    A *myA;
};

Или лучше использовать

чч:

#include "a.h"

Class B
{
    doSomething(A *a);
    A *myA;
};

Ответы [ 5 ]

10 голосов
/ 27 февраля 2012

Использование предварительных объявлений улучшает разъединение . Если вы можете избежать включения "A.h" с помощью предварительного объявления, рекомендуется использовать предварительное объявление. Это лучше не только потому, что ваши сборки выполняются быстрее (в конце концов, предварительно обработанные заголовки могут иметь дело с эффективностью компилятора), но и потому, что это говорит читателям вашей декларации, что структура вашего класса B не зависит от знания чего-либо о вашем класс A, кроме существующего *.

РЕДАКТИРОВАТЬ (чтобы ответить на ваш вопрос) Единственный недостаток, который я знаю, состоит в том, что вы не можете использовать их во всех ситуациях: например, объявление, подобное этому:

class B
{
    A myA[10];
};

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

* Реализация класса B вполне может зависеть от знания деталей класса A. Однако эта зависимость становится деталью реализации B, скрытой от пользователей вашего класса; Вы можете изменить его в любое время, не нарушая код, зависящий от класса B.

2 голосов
/ 08 апреля 2019

Предварительное объявление - единственный способ прервать циклическое включение.

Это главный недостаток, если его не использовать осторожно, я думаю.Я работал в большом проекте, где по возможности делаются предварительные заявления.Циклические зависимости были настоящей проблемой в конце концов.

2 голосов
/ 27 февраля 2012

использование прямого объявления ускоряет время компиляции

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

Реальное улучшение, которое вы видите, когда вы меняете заголовок и вам нужно перекомпилировать.

Форвардное объявление - единственный способ прервать циклическое включение.

1 голос
/ 27 февраля 2012

Я буду говорить на практике.Плюсы:

  1. Избегает циклических зависимостей компилятора.То, как вы написали приведенный выше код, даже не скомпилируется иначе, если вы не поместите A и B. в один заголовок.

  2. Это позволяет избежать зависимостей во время компиляции.Вам разрешено менять ах без перекомпиляции юнитов, включающих bh. По той же причине это ускоряет сборку в целом.Чтобы узнать больше на эту тему, я рекомендую поискать идиому Pimpl.

Минусы:

  1. Ваши основные исходные файлы, вероятно, должны будут использовать больше заголовков (мы не можем создать экземпляр)или работать с A, просто включив Bh).Для меня это достойный обмен на более быстрые сборки.

  2. Это, вероятно, самый большой недостаток, заключающийся в том, что он может быть связан с некоторыми накладными расходами во время выполнения в зависимости от того, что вы делаете.В приведенном вами примере B не может напрямую хранить A как значение.Он включает в себя уровень косвенности, который может также подразумевать дополнительное выделение / освобождение кучи, если B является диспетчером памяти для A (то же самое будет верно для pimpl).Независимо от того, являются ли эти издержки тривиальными или нет, вам нужно провести черту, и стоит помнить, что удобство обслуживания и производительность разработчика определенно важнее микрооптимизации, которая даже не будет заметна для пользователя.Я бы не стал использовать это в качестве причины, чтобы исключить эту практику, если только она определенно не является узким местом или вы заранее знаете, что затраты на выделение / освобождение кучи или косвенное обращение указателя будут нетривиальными накладными расходами..

0 голосов
/ 18 февраля 2014

Единственный недостаток, который приходит на ум, заключается в том, что для предварительных объявлений требуются указатели.Поэтому они не могут быть инициализированы и, следовательно, могут вызвать исключение нулевой ссылки.Как стандарт кодирования, который я сейчас использую, требует, чтобы все указатели требовали проверки нулевой ссылки, если можно добавить много кода.Я начал обходить это с Design By Contract инвариантами;тогда я могу утверждать, что все, что инициализировано в конструкторе, никогда не будет нулевым.

...