这个函数应该是什么类型的对象return?

What type of object should this function return?

考虑这个 class:

class Widget
{
    Widget::Widget();
    bool initialize();
}

一个Widget具有以下特点:

    必须调用
  1. initialize()才能完全构建
  2. initialize() 可能会失败
  3. initialize()

鉴于此,我将创建封装在始终 return 相同 Widget 实例的工厂函数中:

Widget* widget() {
    static auto w = new Widget;
    static auto initialized = false;

    if (!initialized) {
        if (!w->initialize()) {
            return nullptr;
        }
        initialized = true;
    }

    return w;
}

widget()的return类型应该是什么?

特别是,我想以某种方式明确表示 returned Widget 的生命周期将比任何调用者都长,但不引用内部实现。

  1. Return 原始指针并添加说明 "The returned pointer points to an object with static storage duration that will not be deleted before the end of the program" 的注释。这很简单,但不是自我记录。
  2. Return一个std::shared_ptr<Widget>。这是自我记录,但我不喜欢它会引入完全不必要的引用计数开销。
  3. Return 一个 std::unique_ptr<Widget> 带有一个空操作的自定义删除函数。如果调用者将其转换为 shared_ptr.
  4. ,我认为这与 #2 具有相同的感知问题

我投给:

boost::optional<Widget&> widget() {
    static Widget w; // no reason for this to be a pointer
    static bool initialized = false;

    if (!initialized) {
        if (!w.initialize()) {
            return boost::none;
        }
        initialized = true;
    }

    return w;
}

清楚地表明调用者不以任何方式拥有 Widget,调用者 delete 不用担心 Widget,并且很清楚是否还是调用不成功

在这里使用原始指针不是正确的做法吗?它已经表达了限制。它可能会失败(通过返回 nullptr),并且由于它没有对指针作出任何承诺,调用者无法安全地导致它被删除。你得到一个原始指针,你不能假设你被允许对指向对象的生命周期做出任何陈述。

Herb Sutter 在这种情况下的建议(http://herbsutter.com/2013/05/30/gotw-90-solution-factories/ 中的第 4 项)是 return optional

There could be one additional reason the function might have returned a pointer, namely to return nullptr to indicate failure to produce an object. Normally it’s better throw an exception to report an error if we fail to load the widget. However, if not being able to load the widget is normal operation and should not be considered an error, return an optional, and probably make the factory noexcept if no other kinds of errors need to be reported than are communicated well by returning an empty optional.

为了使生命周期和所有权更清晰,我会使用 Singleton pattern 的约定,并使您的函数成为 Widget class 上的静态 getInstance 函数。

class Widget {
  bool initialize();
 public:
  static Widget* getInstance() {
    static Widget w;
    static bool initialized = false;

    if (!initialized) {
      if (!w.initialize()) {
         return nullptr;
      }
      initialized = true;
    }
    return &w;
  }
};

我认为原始指针 return 类型记录了这样一个事实,即调用者不应获得所有权并且它可能为空。

正如其他人所说,如果工厂只生产一件商品,工厂可能不是正确的术语。好像是单例。

考虑到:

  • 我们将只创建一个 Widget 实例
  • 该实例将在有人第一次请求时构建(如果有的话)
  • 该实例将一直存在到程序结束,然后应该被销毁
  • 任何人都不应删除该实例

我会尝试这样的事情:

class Widget {
public:
    static Widget& Instance() {
        static Widget w{};
        return w;
    }

private:
    Widget() {
        // Expensive construction
    }
    Widget(const Widget&) = delete; // avoid copy

};