【问题标题】:Why is this being optimized away by g++? At least, I think that's what's going on为什么这被 g++ 优化掉了?至少,我认为这就是正在发生的事情
【发布时间】:2017-12-02 05:59:58
【问题描述】:

当我运行以下代码时

#include <iostream>
int main(int argc, char *argv []) {
  
  std::string simpleString("this is just a simple string");
  
  std::cout << "simpleString = " << simpleString << std::endl << std::endl;
 
  std::string one = (simpleString + ", one");

  const char * oneCharStar = one.c_str();
  std::cout << "simpleString + one: '" << oneCharStar << "'" << std::endl;

  const char * twoCharStar = (simpleString + ", two").c_str();
  std::cout << "simpleString + two: '" << twoCharStar << "'" << std::endl;

  return 0;
}

在我的 Fedora Core 23 机器上, uname -a 报告:

"Linux glorp 4.5.7-202.fc23.x86_64 #1 SMP 2016 年 6 月 28 日星期二 18:22:51 UTC x86_64 x86_64 x86_64 GNU/Linux"

和 g++ --version 说

“g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)”

第一个输出显示“这只是一个简单的字符串,一个”,而第二个输出显示的是空字符串。

我猜这里正在进行某种优化,但是,在我以前的 Ubuntu 机器(16.mumble,安息吧)上,这段代码运行得如我所料。我刚刚发现,当我在新机器上重新编译我的应用程序(使用相同的 make 文件等)时,此代码如上所示失败。

此外,它在以下平台上也可以正常工作:

$ uname -a Linux t4240rdb

3.12.37-rt51+g43cecda #2 SMP Fri Mar 4 18:18:03 EST 2016 ppc64 GNU/Linux

$ g++ --版本

g++ (GCC) 4.9.2

版权 (C) 2014 Free Software Foundation, Inc.

这里发生了什么?谢谢!

【问题讨论】:

  • 你有未定义的行为。
  • 我在提出问题之前尝试搜索答案。
  • @nzc 是的。你的问题问得很好。但是,当有人更熟悉确切的问题时,他们可能会提出更好的搜索并找到您的答案。这并不意味着你的问题不好。 StackOverflow 上的重复就可以了。
  • 感谢您的解释。
  • “那么为什么像 ().c_str() 这样的表达式有用呢?”可能 std::string::c_str() 最重要的用途是调用 Linux 或 POSIX API 或大型应用程序的前身函数,这些函数需要 c 样式的空终止字符串作为输入。

标签: c++


【解决方案1】:
const char * twoCharStar = (simpleString + ", two").c_str();

在此行之后,临时字符串(simpleString + ", two") 被销毁。

std::string 分配内存,c_str() 返回指向该内存的指针。在std::string 的析构函数中,内存被释放。因此,在这一行之后,twoCharStar 指向已删除的内存。

在释放内存后使用内存是未定义的行为。

【讨论】:

  • 在完整表达式中很有用,但在之后没有用。例如,std::cout &lt;&lt; (&lt;makes-a-string&gt;).c_str() &lt;&lt; std::endl 是完全有效的,因为临时继续存在直到完整表达式结束。
  • @nzc 说得好。更改std::string 以便不能在即将超出范围的对象上调用c_str() 似乎不是一个坏主意。但是,它会破坏代码(如果我理解正确的话)。 someFunctionThatPrintsACString((simpleString + ", two").c_str()) 不会是未定义的行为,因为临时存在直到函数调用之后,但是如果您将 c_str() 更改为在这种情况下不起作用,那么这样的代码将无法编译
  • @nzc 好消息是,一旦你学会了这些模式,它们就会在 C++ 中应用到所有地方。不得不考虑这样的事情是使 C++ 比 Java 或 Python 等语言更难的部分原因。但是能够做这样的事情是 C++ 强大的一部分。抽象至少可以帮助您减少需要考虑的事情,即使您必须注意诸如此类的细节。有些人一直在尝试开发语言或库来解决这些问题,但这并不是一件容易的事
  • @DOUGLASO.MOEN (someString + "some literal") 创建一个std::string,因为std::string 有一个operator+ 采用const char *
  • @nzc 可以说你已经使用 c_str() 打破了抽象。毕竟,整个代码块都可以在没有char * 的情况下编写。如果将所有char * 替换为std::string,则不会出现问题。
猜你喜欢
  • 2023-03-15
  • 2015-03-22
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-06
  • 2016-02-16
相关资源
最近更新 更多