Руководство по стилю Google (раздел «Прямое замедление»)

Предисловие

Руководство по стилю 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 заменить на forward decls для B и D, test () вызовет f (void *).

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

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

Вопрос

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

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

6

Решение

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

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

Что это может означать для зависимости скрытый?

Допустим, ваш файл 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, Предварительные заявления делают это возможным.

2

Другие решения

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

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

Или это что-то присущее Google Code Base?

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

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

0

По вопросам рекламы [email protected]