Руководство по стилю Google (раздел «Вперед» - PullRequest
0 голосов
/ 18 сентября 2018

Предисловие

Руководство по стилю Google содержит список недостатков предварительного объявления

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

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

  3. Прямое объявление символов из пространства имен std :: приводит к неопределенному поведению.

  4. Может быть трудно определить, требуется ли предварительное объявление или полное #include.Замена #include на предварительную декларацию может молча изменить значение кода:

Код:

  // b.h:
  struct B {};
  struct D : B {};

  // good_user.cc:
  #include "b.h"
  void f(B*);
  void f(void*);
  void test(D* x) { f(x); }  // calls f(B*)

Если #include было заменено на прямое decls для Bи D, test () вызовет f (void *).

Объявление в прямом направлении нескольких символов из заголовка может быть более многословным, чем просто # включение заголовка.

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

Вопрос

Меня особенно интересует первый пункт, так как я не могу придуматьс одним сценарием, где прямое уменьшение пропускает необходимую перекомпиляцию при изменении заголовков .Кто-нибудь может сказать мне, как это может произойти?Или это что-то присущее Google Code Base?

Поскольку это первый пункт в списке, он также кажется довольно важным.

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

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

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

Или это что-то присущее базе кодов Google?

Блок размещенного кода о Dимеет смысл.Если вы не #include заголовок, который определяет D, но предоставляют простое предварительное объявление, вызов f(x) преобразуется в f(void*), что не то, что вы хотите.

IMO,Избегать форвардных деклараций в пользу #include использования заголовочных файлов - очень дорогая цена, которую приходится платить только за приведенный выше вариант использования.Однако, если у вас достаточно аппаратных / программных ресурсов, чтобы стоимость #include заголовочных файлов не учитывалась, я могу понять, как можно оправдать такую ​​рекомендацию.

0 голосов
/ 18 сентября 2018

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

Я думаю, что это тоже немного неясно, и, возможно, можно сформулировать немного более четко.

Что может означать, что зависимость будет скрытой?

Допустим, ваш файл main.cc нуждается в header.h для правильной сборки.

  • Если main.cc включает header.h, то это прямая зависимость.

  • Если main.cc включает lib.h, а затем lib.h включает header.h, то это косвенная зависимость.

  • Если main.cc каким-то образом зависит от lib.h, но не генерирует ошибку сборки, если lib.h не включено, то я могу назвать это скрытой зависимостью.

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

Как это происходит?

У меня есть main.c, lib.h и types.h.

Вот main.c:

#include "lib.h"
void test(D* x) { f(x); }

Вот lib.h:

#include "types.h"
void f(B*);
void f(void*);

Вот types.h:

struct B {};
struct D : B {};

Теперь main.cc зависит от types.h для генерации правильного кода. Однако main.cc имеет прямую зависимость только от lib.h, у него есть скрытая зависимость от types.h. Если я использую предварительные объявления в lib.h, то это ломает main.cc. И все же main.cc все еще компилируется!

И причина того, что main.cc прерывается, заключается в том, что он не включает types.h, хотя main.cc зависит от объявлений в types.h. Предварительные заявления делают это возможным.

...