I want to move a NULL std::unique_ptr to a std::shared_ptr, like so:
std::unique_ptr test = nullptr;
std::shared_ptr
The unique_ptr
constructor you are trying to use, which default-constructs the deleter, is ill-formed (before C++17) or disabled by SFINAE (as of C++17) if the deleter type is a pointer, in order to stop you from accidentally creating a unique_ptr
whose deleter is itself a null pointer. If you really want to create such a unique_ptr
, you can do so by explicitly passing a null deleter:
std::unique_ptr<float,void(*)(float*)> test(nullptr, nullptr);
This unique_ptr
object is not very useful, because it can't delete anything.
By using a null std::function
deleter, you've told the compiler "yes, I really want to shoot myself in the foot". Of course, when the last std::shared_ptr
is destroyed, the null std::function
is invoked, and undefined behaviour occurs. What else did you expect?
I'll echo Brian's answer and add that in situations like this where the function shouldn't be null, you can use a function reference, which are nonnullable like all C++ references, instead of function pointers.
void delete_float(float *f) {delete f;}
using Deleter = void(float*);
// Function pointers
constexpr void(*fptr)(float*) = delete_float;
constexpr Deleter *fptr_typedef = delete_float;
constexpr auto fptr_auto = delete_float;
constexpr auto *fptr_auto2 = delete_float;
// Function references
constexpr void(&fref)(float*) = delete_float;
constexpr Deleter &fref_typedef = delete_float;
constexpr auto &fref_auto = delete_float;
The one gotcha you need to keep in mind with function references is that lambdas implicitly convert to function pointers, but not function references, so you need to use the dereference operator *
to convert a lambda to a function reference.
const Deleter *fptr_lambda = [](float *f) {delete f;};
// const Deleter &fref_lambda = [](float *f) {delete f;}; // error
const Deleter &fref_lambda_fixed = *[](float *f) {delete f;};