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

strange behaviors for boost::filesystem::path::string() output

本文关键字:输出 filesystem path string boost      更新时间:2023-10-16

对于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在前2行中为空
  • 为什么2号线p_name不为空,name为空
  • 为什么这个程序在第3行有正确的(?)输出,尽管s_namename之间似乎没有关系

您正在引用临时文件。

如果绑定到const引用(如p_name),则临时的生存期将延长到包含范围的末尾。

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

您应该按值获取filename()(和友元)的返回值(如果类型支持,则在现代编译器上应自动执行移动)。

请注意MSVC"似乎"接受了此代码并"做了你所期望的"——可能是因为它有一个非标准扩展,即使绑定到非常量引用,也可以延长临时变量的生存期。

不错。;-)

name参考。也就是说,它只是引用p.filename().string()。然而,这是一个临时,即它在语句完成后被销毁,留下name来引用无效内存。你在一个行为不明确的国家,幸运的是你的程序没有崩溃。

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

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

不用说,你永远不应该依赖这种行为。