`std::unique_ptr` 的这种行为是预期的吗?

Is this behavior of `std::unique_ptr` expected?

我有一个我一直在做的项目,它使用多态性通过覆盖 encode 函数来实现对象的编码。

现在,这个项目一直在使用指针来实现多态行为。由于我的应用程序相对较新,因此我认为从常规原始指针切换到智能指针不会太困难,因为它们会自动管理内存。

在我的一个函数中,我 return 一个 std::unique_ptr。在 returning 智能指针之后,我立即想要强制转换底层原始指针。因此,对正在发生的事情的过度简化看起来像这样:

std::unique_ptr<something> do_something() {
    return std::unique_ptr<something>(new something());
}

void caller() {
    auto output = static_cast<another*>(do_something().get());
    // Do something with output...
}

我知道 std::unique_ptr 没有复制构造函数,因为它在任何给定时刻只能 "owned" 一次。实现复制构造函数将允许创建重复指针,这与此原则背道而驰。如果我的理解是正确的,下面的代码使用移动构造函数初始化 B,并且不复制 A:

std::unique_ptr<int> get_a() {
    std::unique_ptr<int> A(new int);
    return A;
}

void get_b() {
   auto B = get_a();
}

这正是我想要的行为。但是,在我的示例中,程序大约有一半的时间会崩溃。另一半时间,它 似乎 可以工作,但底层指针的内容只是普通的垃圾。 (我怀疑这是未定义的行为,并且 get() 只是有时 returning 一个可读地址。)

现在,经过一番思考,我得出结论,如果 B 确实是通过移动构造函数初始化的,那么 B 本身必须 而不是 是临时的。但是,在我的第一个示例中,do_something() 的结果是临时的,我正在 移动构建它 !所以我决定停止内联对 do_something() 的调用,然后我立即得到了预期的行为!每次我在临时对象上使用 get() 时,结果都是不可预测的,而且完全是错误的。

我的问题是:

我应该期待 unique_ptr 的这种行为吗?如果是这样,如何记录这种行为? (更具体地说,我的第一个示例是未定义的行为吗?)是否有任何替代方法(shared_ptr,也许?)可以让我内联函数调用并仍然获得预期的结果?

这里的关键在你的语句中总结了"they would automatically manage memory".

你的 unique_ptr (post-move) 是一个临时的,在声明 output 之后立即超出范围,使用动态分配的 int它并留下 output 悬空。

暂时的。 临时!如此命名是有充分理由的……

这种行为在很多很多地方都是 "documented":存储指向超出范围的对象的指针是一个非常糟糕的主意,从今以后 使用 该指针完全损坏(是的,它是 UB)。

你不能通过切换到其他智能指针来解决这个问题,不:停止 "inlining" 函数调用(并停止使用这个术语;那不是 "inlining" 的意思)并确保只要你想通过指针访问它,对象就存在。

auto ptr    = do_something();
auto output = static_cast<another*>(ptr.get());