You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统一处理返回unique_ptr的工厂函数与全局对象引用获取函数?

C++场景下的对象选择方案

不可修改的基础代码

首先存在以下不可修改的代码:

全局Foo对象定义

struct Foo {
    int i;
    ~Foo() { std::cout << "gone: " << i << std::endl; }
};

Foo globalFoo{7};

获取全局对象的函数

Foo& getFoo() {
    return globalFoo;
}

创建新对象的工厂函数

std::unique_ptr<Foo> makeFoo() {
    return std::make_unique<Foo>(5);
}

客户端需求

在客户端代码中,需要根据运行时输入的布尔值b,决定使用全局对象(通过getFoo()获取)还是创建新的Foo对象(通过makeFoo()获取),代码框架如下:

int main()
{
    bool b{false};

    std::cin >> b;

    /* type */ foo = b
                   ? /* via getFoo */
                   : /* via makeFoo */;
} 

不可行的方案分析

以下两种常见做法均存在问题:

方案1:直接使用引用导致悬垂

auto& foo = b
          ? getFoo()
          : *makeFoo();

问题:makeFoo()返回的临时unique_ptr会在表达式结束后立即销毁,其管理的Foo对象也会被随之销毁,导致foo变成悬垂引用。

方案2:使用release()导致内存泄漏

auto& foo = b
          ? getFoo()
          : *makeFoo().release();

问题:调用release()会让unique_ptr放弃对Foo对象的所有权,若后续不手动调用delete,该对象会发生内存泄漏;手动调用delete又会增加代码复杂度,且容易遗漏。

合适的处理方式

可以通过一个局部的unique_ptr来管理动态创建的对象,同时用引用指向目标对象,确保两者生命周期一致:

int main()
{
    bool b{false};
    std::cin >> b;

    std::unique_ptr<Foo> owned_foo;
    Foo& foo = b ? getFoo() : *(owned_foo = makeFoo());
    
    // 这里可以正常使用foo
}
  • 当b为true时,foo直接引用全局对象,owned_foo保持为空,不会产生额外内存管理操作。
  • 当b为false时,makeFoo()返回的unique_ptr被赋值给owned_foo,foo引用该动态创建的对象;owned_foo会在main函数结束时自动销毁其管理的Foo对象,避免内存泄漏,同时保证foo在整个main函数内都是有效的引用。

另一种更类型安全的方案是使用std::variant来存储两种可能的对象持有方式:

#include <variant>
#include <functional> // 用于std::reference_wrapper

int main()
{
    bool b{false};
    std::cin >> b;

    std::variant<std::reference_wrapper<Foo>, std::unique_ptr<Foo>> foo_container = 
        b ? std::ref(getFoo()) : makeFoo();

    // 通过std::visit获取统一的Foo引用
    Foo& foo = std::visit([](auto&& val) -> Foo& {
        if constexpr (std::is_same_v<std::decay_t<decltype(val)>, std::reference_wrapper<Foo>>) {
            return val.get();
        } else {
            return *val;
        }
    }, foo_container);
    
    // 正常使用foo
}

这种方式明确区分了"引用全局对象"和"持有动态对象"两种状态,类型安全性更高,适合复杂场景。

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 09:20:22