I have c-Structure that I want to embed in an cpp class without poisoning of my global namespace so I do not want to include the c-header.
That's why I want to use a smart scoped pointer (QScopedPointer
or boost::scoped_ptr
) with a forward declared structure name.
What I do not understand is the implementation of both mentioned scoped pointers that fails on compile:
boost:
error C2027: use of undefined type 'xxx'
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here
(void) sizeof(type_must_be_complete);
delete x;
}
and the same in Qt:
error C2027: use of undefined type 'xxx'
template <typename T>
struct QScopedPointerDeleter
{
static inline void cleanup(T *pointer)
{
// Enforce a complete type.
// If you get a compile error here, read the section on forward declared
// classes in the QScopedPointer documentation.
typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; // < here
(void) sizeof(IsIncompleteType);
delete pointer;
}
};
The referenced documentation did not helped me. it says that the destructor of the forward declared class does not have to be inline and must be available at every possible instantiation of the cleanup of the scoped pointer. But my c-structure does not have an destructor.
So I have 2 questions:
my c-Structure does not have a destructor.
For one thing, No. Your struct actually have a destructor - implicitly-declared destructor.
Anyway, let's go ahead.
delete pointer;
When compiling this code, we should call the destructor of *pointer
. However, if *pointer
is incomplete type, we can't know the destructor to call. In this case, standard [expr.delete] says it causes undefined behavior.
If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.
As you can see, if your struct doesn't have non-trivial destructor or a deallocation function (class-specific operator delete
), it's not UB. However, you probably can add a destructor into your struct - you will do. If you do without fixing this point, it becomes really buggy bug. (Compiler doesn't have to report it; it's just UB, not illegal code.) So it's not considered as a good practice.
Because of this, deleting incomplete types is really what we should avoid. To avoid that, we uses this trick.
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here
(void) sizeof(type_must_be_complete);
Since sizeof(T)
is illegal code if T
is incomplete type, so it can reduce compile-time error before your program goes being crazy due to UB.
I highly recommend you to just include it despite slower compliation speed; Although your struct is trivial and doesn't have operator delete
, they can be added without fixing, which causes UB.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With