boost :: filesystem :: path :: string()输出的奇怪行为

时间:2014-09-11 12:58:53

标签: c++ string boost

pf.string()输出似乎有一些奇怪的行为,其中pf是使用p.filename()生成的,其中p的类型为boost::filesystem::path,并使用 char const * 或 std :: string

以下是代码段:

#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

int main(int argc, char **argv) {
  fs::path p(argv[0]);  // or fs::path p((std::string(argv[0])));
  fs::path &&pf = p.filename(); // or fs::path pf = p.filename();
  std::string const &name = p.filename().string();
  std::cout << "*" << name << "*\n";
  std::string const &p_name = pf.string();
  std::cout << "*" << p_name << "*\t";
  std::cout << "*" << name << "*\n";
  std::string s_name = p.filename().string();
  std::cout << "*" << s_name << "*\t";
  std::cout << "*" << name << "*\n";
  return 0;
}

这里的argv[0]fs.out,可执行文件的输出(使用clang3.4 / gcc4.9-O3 / -O0编译)是:

**
*fs.out*    **
*fs.out*    *fs.out*

我使用的提升版本 1.55 来自 Debian jessie(测试)包。

我的问题:

  • 前两行为什么name为空?
  • 为什么p_name不为空,但第2行name为空?
  • 为什么这个程序在第3行有正确的(?)输出,尽管似乎s_namename之间没有关系?

2 个答案:

答案 0 :(得分:4)

你正在参考临时工。

Iff绑定到const引用(如p_name),临时的生命周期将扩展到包含范围的末尾。

否则您只是调用未定义的行为。这也解释了当您分配给完全不同的变量时name如何变化。这显然是因为s_name 发生来分配name仍然(错误地!)所引用的相同内存块。可能会发生更糟糕的事情。

您应该按值filename()(以及朋友)的返回值(如果类型支持,则应该在现代编译器上自动表现为 move 。)

注意 MSVC“出现”接受此代码并“按照您的意愿行事” - 大概是因为它有一个非标准扩展,即使在绑定时也可以延长临时生命周期非const引用。

答案 1 :(得分:3)

好的一个。 ; - )

name参考。即,只有引用到p.filename().string()。但是,这是一个临时,即在语句完成后它会被销毁,让name引用无效的内存。你处于未定义的行为国家,幸运的是你的程序没有崩溃。

(关于你的第二个问题,const &上的细则更新了我,所以给他+1。)

在第三轮中,s_name对象,即它拥有p.filename().string()副本(因此有效)。幸运的是,编译器显然在name引用的相同位置创建了该对象...

毋庸置疑,你不应该依赖这种行为。