There is a nice little technique here to allow the use of std::unique_ptr
with incomplete types.
Here is the relevant code:
// File: erasedptr.h
#include <memory>
#include <functional>
// type erased deletor (an implementation type using "veneer")
template <typename T>
struct ErasedDeleter : std::function<void(T*)>
{
ErasedDeleter()
: std::function<void(T*)>( [](T * p) {delete p;} )
{}
};
// A unique_ptr typedef
template <typename T>
using ErasedPtr = std::unique_ptr<T, ErasedDeleter<T>>;
// Declare stuff with an incomplete type
struct Foo;
ErasedPtr<Foo> makeFoo();
// File: main.cpp (Foo's definition is not available in this translation unit)
#include "erasedptr.h"
int main() {
ErasedPtr<Foo> f; // [R1]
f = makeFoo();
// ~Foo() gets called fine
}
// File: foo.cpp
#include <iostream>
#include "erasedptr.h"
struct Foo {
~Foo() { std::cout << "~Foo()\n" ; }
};
ErasedPtr<Foo> makeFoo() { return ErasedPtr<Foo>(new Foo); }
This works on all compilers I tried: gcc 4.9, clang 3.5, and msvc VS13 and VS15. But they all generate the following warning:
deletion of pointer to incomplete type 'Foo'; no destructor called
If [R1] above is replaced with ErasedPtr<Foo> f( makeFoo() );
, the warning does not manifest.
At the end, the destructor does get called and there doesn't seem to be an actual problem. The warning is problematic, because it can not be ignored in quality-critical environments, and this otherwise very useful pattern is unavailable.
To reproduce, create the 3 files erasedptr.hpp
, main.cpp
, foo.cpp
as above and compile.
So the question is: what is going on? Could there be any alternative implementation to circumvent this warning?