To understand enum , start by looking at the destructor without it:
~scoped_ptr() { delete ptr_; }
where ptr_ is C* . If type C is incomplete at this point, then all the compiler knows is struct C; , then (1) the default do-nothing destructor created is used for the specified instance of C. This is unlikely to be correct for an object controlled by a smart pointer.
If deleting with a pointer to an incomplete type always had an Undefined Behavior, then the standard could simply require the compiler to diagnose it and complete the failure. But it is clearly defined when the real destructor is trivial: the knowledge that a programmer can have, but the compiler does not have. Why does the language define and allow this above me, but C ++ supports many practices that today are not considered as best practices.
A full type has a known size, and therefore sizeof(C) will compile if and only if C is a full type - with a known destructor. Therefore, it can be used as a guard. One way is just
(void) sizeof(C);
I would suggest that with some compilers and parameters, the compiler optimizes it before it can notice that it should not compile and that enum is a way to avoid such inappropriate compiler behavior:
enum { type_must_be_complete = sizeof(C) };
An alternative explanation for choosing enum , rather than just a dropped expression, is simply personal preference.
Or as James T. Hagget suggests in a comment on this answer: "Enumeration can be a way to create a pseudo-portable error message at compile time."
(1) The default do-nothing destructor for an incomplete type was a problem with the old std::auto_ptr . It was so insidious that he crawled into the GOTW element about the PIMPL idiom written by the chairman of the international standardization committee C ++ Herb Sutter. Of course, std::auto_ptr deprecated now, some other mechanism will be used instead.
Cheers and hth. - Alf Nov 19. '15 at 10:24 2015-11-19 10:24
source share