我想将NULL std :: unique_ptr 移动到 std :: shared_ptr ,如下所示:
std::unique_ptr<float> test = nullptr;
std::shared_ptr<float> test2 = std::move(test);
据我所知,这样做应该是合法的,并且它在Visual Studio 2015和GCC中运行良好。
但是,对于具有删除声明的 std :: unique_ptr ,我不能这样做,如下所示:
std::unique_ptr<float,void(*)(float*)> test = nullptr;
std::shared_ptr<float> test2 = std::move(test);
上面的代码不能在visual studio中编译,并且会触发静态断言失败“错误C2338:使用空删除指针构造的unique_ptr”。
我可以使用 std :: function 删除器,在这种情况下可以规避静态断言失败:
std::unique_ptr<float,std::function<void(float*)>> test = nullptr;
std::shared_ptr<float> test2 = std::move(test);
在这种情况下,代码编译得很好,但是一旦 test2 的 std :: shared_ptr 副本被销毁,我就会中止。
为什么后两种情况如此成问题?
奇怪的是,如果我将 test2 的类型从 std :: shared_ptr 更改为 std :: unique_ptr ,第二种情况仍会触发静态断言失败,但案例1和案例3都可以正常工作:
{
std::unique_ptr<float> test = nullptr;
std::unique_ptr<float> test2 = std::move(test); // Works fine
}
{
//std::unique_ptr<float,void(*)(float*)> test = nullptr; // triggers a static assert failure
//std::unique_ptr<float,void(*)(float*)> test2 = std::move(test);
}
{
std::unique_ptr<float,std::function<void(float*)>> test = nullptr;
std::unique_ptr<float,std::function<void(float*)>> test2 = std::move(test); // Works fine
}
答案 0 :(得分:4)
你试图使用的unique_ptr
构造函数,默认构造删除器,是不正确的(在C ++ 17之前)或由SFINAE(从C ++ 17开始)禁用(如果删除类型)是一个指针,以阻止您意外创建一个unique_ptr
,其删除器本身就是一个空指针。如果你真的想创建这样的unique_ptr
,可以通过显式传递空删除器来实现:
std::unique_ptr<float,void(*)(float*)> test(nullptr, nullptr);
此unique_ptr
对象不是很有用,因为它无法删除任何内容。
通过使用null std::function
删除器,你已经告诉了编译器&#34;是的,我真的想要自己在脚下拍摄&#34;。当然,当最后一个std::shared_ptr
被销毁时,将调用null std::function
,并发生未定义的行为。您还期待什么?
答案 1 :(得分:0)
我会回应Brian的回答并在这样的情况下补充一点,在这种情况下函数不应为null,你可以使用一个函数 reference,,这是无法使用的像所有C ++引用一样,而不是函数指针。
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;
你需要记住函数引用的一个问题是lambdas隐式转换为函数指针,而不是函数引用,因此你需要使用解引用运算符*
将lambda转换为函数引用
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;};