【问题标题】:Return const reference to local variable correctly正确返回对局部变量的 const 引用
【发布时间】:2015-06-23 15:17:30
【问题描述】:

除了答案123GotW88,假设以下方法

QString createString()
{
    return QString("foobar");
}

const QString& getString()
{
    return createString();
}

这将在 VS2013 中产生著名的“警告 C4172:返回局部变量或临时地址”。

现在,如果我将第二种方法更改为

const QString& getString()
{
    const QString& binder = createString();
    return binder;
}

不再报告错误。这是在不更改 API 签名的情况下修复警告的安全方法吗?为什么会这样?

【问题讨论】:

  • 为什么不让createString() 简单地从new QString 返回指针?然后调用者拥有该字符串,并且可以根据需要保存、删除或引用它。
  • @donjuedo 这是一个可怕的想法。不涉及指针,在这种情况下手动管理内存是完全没有根据的。
  • @pmr,恕我直言,我不同意。创建对象,但既没有变量名也没有指针,在使用新对象时会留下尴尬的情况。
  • 如果您需要在指针中返回某些内容,请始终使用 std::unique_ptr 或 std::shared_ptr(或任何其他替代方法,例如来自 Boost)并按值返回该智能指针。但是在问题中的代码中,最好只返回一个值。
  • @donjuedo QString 一个指针。确切地说,它是指针的包装器。见:code.woboq.org/qt5/qtbase/src/corelib/tools/…

标签: c++ qt


【解决方案1】:

它不起作用。这样,您只需通过使情况更难分析来抑制警告。行为仍未定义。

【讨论】:

  • 有没有办法让它在不改变方法签名的情况下工作?
  • @x29a:您必须将引用绑定到非本地和非临时的东西。如果您有一些非本地和非临时性的东西可以用于该目的,那么请继续使用它。一个低质量的快速修复方法是使用QString 类型的内部static 变量。但是返回对独立存在的非本地和非临时实体的引用通常会使函数不可重新输入,这也不是一件好事。
  • 我猜该方法必须返回一个副本。谢谢!
  • QString 已经实现了一个移动构造函数,所以你可以通过一个值返回它而不用担心性能。
  • @MarianSpanik 我知道,我更害怕破坏任何接口,但考虑再久一点,我无法想象方法必须返回引用而不是副本的场景。不过还是谢谢。
【解决方案2】:

你的“修复”没有。

要保留签名,您必须做出一些权衡。至少,getString 是不可重入的,除了返回字符串的副本之外无法修复。它也不是线程安全的,尽管无需更改签名即可修复。

至少,要保留签名,您必须自己保留字符串。一个简单的解决方案可能如下所示:

const QString & getString() {
  static QString string = createString();
  return string;
}

如果你的函数真的是一个方法,另一种方法是让字符串成为类成员:

class Foo {
  QString m_getString_result;
public:
  const QString & getString() {
    m_getString_result = createString();
    return m_getString_result;
  }
};

为了线程安全,您需要将结果保存在线程本地存储中。这仍然无法解决重入问题 - 因此,鉴于您拥有的签名,它无法修复。

【讨论】:

    【解决方案3】:

    此行为未定义。

    const QString& getString()
        {
            const QString& binder = createString();
            return binder;
        }
    

    一旦binder 超出范围。它不再被定义。 您可以通过保持活页夹活动来定义它。

    【讨论】:

    • 请注意他的createString()返回的是QString,而不是QString&
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-14
    • 2021-04-11
    相关资源
    最近更新 更多