Щоб зрозуміти enum
, почніть з розгляду деструктора без нього:
~scoped_ptr() {
delete ptr_;
}
де ptr_
a C*
. Якщо C
на даний момент тип є неповним, тобто все, що знає компілятор struct C;
, то (1) для екземпляра C, на який вказано, використовується згенерований за замовчуванням деструктор бездіяльності. Це навряд чи буде правильно робити для об’єкта, керованого розумним вказівником.
Якщо видалення за допомогою вказівника на неповний тип завжди мало невизначену поведінку, тоді стандарт міг просто вимагати від компілятора його діагностування та помилки. Але це чітко визначено, коли справжній деструктор є тривіальним: знання, які може мати програміст, а компілятор - не. Чому мова визначає та допускає це, мені не під силу, але C ++ підтримує багато практик, які сьогодні не розглядаються як найкращі практики.
Повний тип має відомий розмір, а отже, sizeof(C)
буде скомпільований тоді і тільки тоді, якщо C
це повний тип - з відомим деструктором. Тож його можна використовувати як охорону. Один із способів був би просто
(void) sizeof(C);
Я гадаю, що за допомогою деякого компілятора та параметрів компілятор оптимізує його, перш ніж він помітив, що він не повинен компілювати, і що enum
це спосіб уникнути такої невідповідної поведінки компілятора:
enum { type_must_be_complete = sizeof(C) };
Альтернативним поясненням вибору, enum
а не просто відкинутого виразу, є просто особисті переваги.
Або, як припускає Джеймс Т. Хаггет у коментарі до цієї відповіді, "перерахування може бути способом створення псевдопортативного повідомлення про помилку під час компіляції".
(1) Згенерований за замовчуванням деструктор бездіяльності для неповного типу був проблемою зі старим std::auto_ptr
. Це було настільки підступно, що він потрапив у пункт GOTW про ідіому PIMPL , написаний головою міжнародного комітету стандартизації С ++ Херб Саттер. Звичайно, сьогодні, коли std::auto_ptr
це застаріло, замість цього буде використовуватися інший механізм.
ptr_
себеsizeof
як,sizeof(*ptr_)
а не якsizeof(C)
.