【问题标题】:How to declare a function which creates an object which will never be null?如何声明一个创建一个永远不会为空的对象的函数?
【发布时间】:2014-04-06 14:03:16
【问题描述】:

我有一个函数可以创建一个对象 QMenu(在堆中)

QMenu* createMenu(QWidget* parent); // parent will takes ownership of the menu

函数永远不会返回空指针。但我认为声明并没有说明这一点,因为它返回了一个指针。因此在使用该方法时,我需要

if (QMenu* m = createMenu(parent))
    m->...

这很烦人。如果它返回一个引用,它就说明了这一点。

QMenu& createA(QWidget* parent);

我从来没有见过这样声明的代码。这个可以吗?有没有更好的声明?

【问题讨论】:

  • 引用版本不起作用,因为您无法返回对本地对象的引用。如果您的函数执行return *new X; 之类的操作,那么它比原始版本更令人困惑,因为调用者必须记住在某些时候执行delete &m;
  • 也许您可以使用 createMenu 函数上的 throw 规范来记录您的意图,甚至可能是“返回有效的 QMenu,或抛出 FooException”的注释
  • 返回本地对象的指针也是无稽之谈。我认为“创建”这个词通常意味着在堆上新建一个对象。
  • 我建议返回一个new'd 对象,并说期望调用者之后执行delete &m; 是不好的设计(但期望他们执行delete m; 是可以的)。跨度>

标签: c++ pointers reference nullptr


【解决方案1】:

只需记录它不返回 null。作为一种解决方案,它并不完全是高科技,但您会发现它在实践中效果很好。

既然很明显你的函数不会返回 null,你就不必写了:

if (QMenu* m = createMenu(parent))
    m->...

你只要写:

QMenu* m = createMenu(parent);
m->...

想一想:要么你需要if 以某种形式检查——但函数永远不会返回 null 是不正确的。

或者函数真的永远不会返回 null。那么if检查就没用了。

话虽如此,您仍然可以在那里添加一个断言以更加安全:

QMenu* m = createMenu(parent);
assert(m != nullptr); // if you use C++11; otherwise assert(m != 0);
m->...

这意味着“如果m为null,那么我自己的代码搞砸了,程序出错了。如果发生这种情况,请尽快退出程序!”

【讨论】:

    【解决方案2】:

    是的,如果函数自行安排对象生命周期的所有权,则可以通过引用返回创建的对象。

    执行此操作的函数的一个重要示例:V& std::map<K,V>::operator[](const K&);

    【讨论】:

      【解决方案3】:

      最简单最清晰的方法是返回一个值:

      A createA();
      

      通常,如果您需要在“堆”上分配资源,一个好的策略是设计A 以便它自己处理这些资源。

      【讨论】:

      • 这种方式我认为它仍然需要处理A的资源,这些资源永远不会告诉资源是否为空。
      • 实际上是一个不错的答案——省略所有这些内存泄漏设计。
      • @user1899020 在没有更多信息的情况下很难说。 A 的职责是什么?为什么需要“在堆中”分配?
      • 如果A 不可复制,这将不起作用。我这样说是因为我怀疑 OP 询问的类是不应复制的 GUI 组件。
      • @MattMcNabb:没问题,因为您可以轻松返回代理(例如,如果它不应该拥有任何东西,则包装 std::weak_ptr)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      相关资源
      最近更新 更多