【问题标题】:Spurious warning about binding temporary to reference member in constructor关于在构造函数中将临时绑定到引用成员的虚假警告
【发布时间】:2014-10-23 01:24:42
【问题描述】:

我知道如果一个临时对象绑定到构造函数的初始化列表中的引用成员,该对象将在构造函数返回时被销毁。

不过,请考虑以下代码:

#include <functional>
#include <iostream>

using callback_func = std::function<int(void)>;

int
func(const callback_func& callback)
{
  struct wrapper
  {
    const callback_func& w_cb;
    wrapper(const callback_func& cb) : w_cb {cb} { }
    int call() { return this->w_cb() + this->w_cb(); }
  };
  wrapper wrp {callback};
  return wrp.call();
}

int
main()
{
  std::cout << func([](){ return 21; }) << std::endl;
  return 0;
}

这对我来说看起来完全正确。 callback 对象将在 func 函数的整个执行过程中存在,不应为 wrapper 的构造函数制作临时副本。

确实,GCC 4.9.0 在启用所有警告的情况下编译良好。

但是,GCC 4.8.2 编译器给了我以下警告:

$ g++ -std=c++11 -W main.cpp 
main.cpp: In constructor ‘func(const callback_func&)::wrapper::wrapper(const callback_func&)’:
main.cpp:12:48: warning: a temporary bound to ‘func(const callback_func&)::wrapper::w_cb’ only persists until the constructor exits [-Wextra]
     wrapper(const callback_func& cb) : w_cb {cb} { }
                                            ^

这是误报还是我误解了对象的生命周期?

这是我测试的确切编译器版本:

$ g++ --version
g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ --version
g++ (GCC) 4.9.0 20140604 (prerelease)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

【问题讨论】:

  • 关闭优化会给我一个段错误。 Valgrind 指出问题出在func(std::function&lt;int ()&gt; const&amp;)::wrapper::call() 附近。
  • 使用 w_cb {cb} 会导致我违反分段。使用w_cb(cb) 不会遇到同样的问题。在 g++ 4.8.3 中测试。
  • 我可以使用 GCC 4.8.2 重现 Valgrind 错误。 (不是段错误,很难,程序输出 42 并按预期成功退出。) GCC 4.9.0 生成的可执行文件是 Valgrind-clean。这些观察结果不会随着优化级别的不同而改变。
  • 我很震惊听到它在某些系统上失败了。 FWIW,在 ideone 的默认设置下工作正常(GCC 4.8.1,{cb})。

标签: c++ c++11 g++ object-lifetime


【解决方案1】:

这是 gcc 4.8 中的一个错误,已在 4.9 中修复。这是错误报告:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50025

【讨论】:

  • 该错误不是警告,而是警告 警告您的事实,这一事实会很有用。我必须去链接来确定...即,实际上是在 gcc 4.8 中创建了一个临时的,并且持续时间不够长。优化可能会导致临时文件不存在?
  • 是的,这解释了发生了什么。感谢您的链接。我受到它的启发做了一些进一步的研究,并将其作为答案发布,但我会接受你的。
  • 这是标准中的一个错误,GCC 正在实施标准的精确措辞,要求在那里创建一个临时文件。 DR 1288 修正了标准。
【解决方案2】:

正如 Howard Hinnant 所指出的以及 R Sahu 的评论中已经指出的那样,这是 GCC 4.8 处理方式中的一个错误(这曾经是当时被打破的标准所要求的;感谢 Tony D 指出这一点)初始化列表。

在我的原始示例中更改构造函数

wrapper(const callback_func& cb) : w_cb {cb} { }

wrapper(const callback_func& cb) : w_cb (cb) { }

使 GCC 4.8.3 的警告消失,并清除创建的可执行 Valgrind。两个汇编文件的差异很大,所以我不在这里发布。 GCC 4.9.0 为两个版本创建相同的汇编代码。

接下来,我将std::function 替换为用户定义的结构,并删除了复制和移动构造函数和赋值运算符。实际上,在 GCC 4.8.3 中,这保留了警告,但现在也给出了一个(稍微更有帮助的)错误,即上述代码行调用了结构的已删除复制构造函数。正如预期的那样,与 GCC 4.9.0 没有区别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2015-04-02
    • 2012-12-03
    • 2021-10-04
    相关资源
    最近更新 更多