如何将没有自定义删除器的 unique_ptr 移动到另一个具有自定义删除器的 unique_ptr?

tte*_*tle 1 c++ unique-ptr move-semantics

#include <memory>
#include <functional>
#include <iostream>

struct TestStruct {
    int a = 100;
};

struct StructDeleter {
    void operator()(TestStruct *ptr) const {
        delete ptr;
    }
};

std::unique_ptr<TestStruct, StructDeleter> MakeNewStruct() {
    std::unique_ptr<TestStruct> st(new TestStruct());

    std::unique_ptr<TestStruct, StructDeleter> customDeleterSt(std::move(st));
    std::cout << customDeleterSt->a << std::endl;
    return customDeleterSt;
}

int main() {
    auto a = MakeNewStruct();
    std::cout << a->a << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码无法编译,如何st移至customDeleterSt?我st从创建界面获得了一个 unique_ptr st,并使用自定义删除器对用户隐藏了 的实现st,那么如何将没有自定义删除器的 unique_ptr 移动到具有自定义删除器的 unique_tr 呢?

谢谢你的帮助!

How*_*ant 6

正如评论中所指出的,暴力方式是让源.release()到目标的构造函数。然而,有一个更优雅的解决方案(恕我直言):

std::default_delete<TestStruct>添加从to的隐式转换StructDeleter

struct StructDeleter {
    StructDeleter(std::default_delete<TestStruct>) {}  // Add this

    void operator()(TestStruct *ptr) const {
        delete ptr;
    }
};
Run Code Online (Sandbox Code Playgroud)

现在,代码可以使用现有的移动构造语法。

无论这是通过转换构造函数完成的,还是.release(),如果StructDeleter不能(出于某种原因)正确删除std::default_delete处理的指针,这将导致未定义的行为。只是因为StructDeleter调用delete ptr,这些技术才有效。

正如所写的,TestStruct在 时不需要是完整的类型delete。但是,如果要TestStruct获取一个重要的析构函数,您还需要确保对于任何调用 的代码StructDeleter::operator()(TestStruct*),这TestStruct是一个完整的类型,否则您将再次回到 UB 领域。 这种保证是对您有用但(按书面形式)不为您做的事情之一。std::default_delete<TestStruct>StructDeleter

如果想要保持~TestStruct()琐碎,最好添加:

static_assert(std::is_trivially_destructible<TestStruct>::value);
Run Code Online (Sandbox Code Playgroud)