Today, I came across a confusing compilation error with MS VC++ using a std::unique_ptr with a custom deleter.
Here the code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <memory> #include <string> typedef void (*void_delete)(void *); template<typename T> void void_deleter(void * ptr) { delete reinterpret_cast<T*>(ptr); } std::unique_ptr<void, void_delete> f1() { return std::unique_ptr<void, void_delete>(new std::string("haha"), void_deleter); } std::unique_ptr<void, void_delete> f2() { return std::unique_ptr<void, void_delete>(nullptr); } |
The compiler complains :
1 2 3 4 5 6 7 8 9 10 11 12 13 | c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(2218): error C2338: unique_ptr constructed with null deleter pointer 1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(2214) : while compiling class template member function 'std::unique_ptr::unique_ptr(std::nullptr_t)' 1> with 1> [ 1> _Ty=void, 1> _Dx=void_delete 1> ] 1> c:\sources\source1.cpp(9) : see reference to class template instantiation 'std::unique_ptr' being compiled 1> with 1> [ 1> _Ty=void, 1> _Dx=void_delete 1> ] |
The gotcha is that the compiler complains of a reference to class template instantiation on line 9. This is the definition of f1().
However, the actual issue is on line 13 in the implementation of f2(). A std::unique_ptr is instantiated with a nullptr and no deleter. The nullptr constructor has a static_assert that protects from uninitialized function-pointer deleter. I wonder what could go wrong with an uninitialized function pointer …
The compiler gives you the line of the first appearance of std::unique_ptr in the compilation unit not the actual line that causes the error … Easy enough to spot on a trimmed down example like this one. It tooks me quite some time to find in a code file with several hundred lines of code and many changes at once.