【问题标题】:How to deal uniformly with a factory returning unique_ptr and a getter returning a reference to global object?如何统一处理返回 unique_ptr 的工厂和返回全局对象引用的 getter?
【发布时间】:2023-02-02 17:04:30
【问题描述】:

假设有一个全局的Foo对象,

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

Foo globalFoo{7};

它可以通过一个通过引用返回它的函数来检索,

Foo& getFoo() {
    return globalFoo;
}

并且还有一个工厂功能可以凭空制作一个不同的Foo

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

以上是不变的。

在客户端代码中,是否应该使用makeFoogetFoo由运行时bool决定。

int main()
{
    bool b{false};

    std::cin >> b;

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

处理这种情况的适当方法是什么?

我可以说这不是方法:

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

因为 foo 在创建 as the temporary result of makeFoo(), the unique_ptr will be destoryed 之后是一个悬空引用,因此将托管 Foo 带走。

这也不是办法:

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

because the object *makeFoo().release() is leaked,除非I manually delete it

【问题讨论】:

  • 可以复制对象吗?或者您是否需要使用对原始对象的引用(在全局变量的情况下)?

标签: c++ memory-management c++17 smart-pointers unique-ptr


【解决方案1】:

您可以使用不执行任何操作的删除器将结果包装在 shared_ptr 中,以防这是一个全局对象。与 unique_ptr 不同,deleter 不是智能指针本身类型的一部分,因此两种情况下的类型都是相同的。

是这样的:


    auto foo = b
                   ? std::shared_ptr(&/* via getFoo */, [](Foo*){})
                   : std::shared_ptr(/* via makeFoo */);

【讨论】:

    【解决方案2】:

    调用getFoo()时,您不拥有该对象,但对于makeFoo(),您拥有它。

    所以你可以将它们存储为两种类型。

    但是你可以参考它:

    unique_ptr<Foo> ufoo;
    Foo* ref{};
    if(b) {
      ufoo = makeFoo();
      ref = ufoo.get();
    } else {
      ref = &getFoo();
    }
    

    那就拿ref做进一步的使用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 2013-01-23
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多