是否可以为另一个对象重用智能指针的内存?

Is it possible to reuse a smart pointer's memory for another object?

假设我有两个大小完全相同的不相关类型。

struct Foo { ... };
struct Bar { ... };

现在,假设我有一棵 Foo 的树,我想将其转换为 Bar.

的树
template <typename Leaf>
struct Tree
{
    Leaf data;
    std::unique_ptr<Tree> lhs;
    std::unique_ptr<Tree> rhs;
};

Tree<Foo> footree = ...;
Tree<Bar> bartree = convert(std::move(footree)); // <--

如何在重用 footree 的堆分配内存的同时执行此转换?换句话说,我如何(安全地)将 Tree<Foo> 转换为 Tree<Bar> 而不分配额外的内存?

这是我实际尝试做的一个简化示例。实际上 FooBar 是递归变体,具有不同数量的替代类型。

对于原始指针,这并不困难。只需手动触发 Foo 的析构函数并通过放置 new 手动应用构造函数。 enable_if 是确保大小和对齐匹配的 SFINAE。

#include <iostream>
#include <vector>

template<typename U, typename V, typename... Args,
         std::enable_if_t<sizeof(U) == sizeof(V) && alignof(U) == alignof(V), int> = 0>
U* repurpose_raw_ptr(V* ptr, Args&&... args)
{
    ptr->~V();
    return new ((void*)ptr) U(std::forward<Args>(args)...);
}

int main()
{
    std::vector<int>* X = new std::vector<int>({1,2,3,4,5});
    std::vector<double>* Y =
        repurpose_raw_ptr<std::vector<double>>(X,
            std::initializer_list<double>{1.,2.,3.,4.,5.});

    std::cout << Y->at(0) << " " << Y->at(4);

    delete Y;

    return 0;
}

您可以应用函数从 std::unique_ptr<Foo>“转换”为 std::unique_ptr<Bar>,方法是使用释放对象所有权的唯一指针的 release() 方法。类似于:

std::unique_ptr<Bar> X = ...;
std::unique_ptr<Foo> Y = std::unique_ptr<Foo>(repurpose_raw_ptr<Bar>(X.release(),...));

这里假设 delete Foodelete Bar 与 Foo/Bar 的销毁 + 原始指针的释放相同,我相信情况可能并非总是如此。

一般来说,我不建议这样做,因为在跨平台环境中很难确保结构具有相同的size/alignment。

编辑:以前,错过了您想以某种方式将 Foo 转换为 Bar。您必须在别处临时 copy/move 实例 Foo 然后触发内存重新调整用途。