【问题标题】:strange behaviors for boost::filesystem::path::string() outputboost::filesystem::path::string() 输出的奇怪行为
【发布时间】:2014-09-11 12:58:52
【问题描述】:

pf.string() 输出似乎有一些奇怪的行为,其中pf 是用p.filename() 生成的,其中pboost::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*

我使用的 boost 版本是 Debian jessie(testing) 包中的 1.55

我的问题:

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

【问题讨论】:

    标签: c++ string boost


    【解决方案1】:

    您正在参考临时人员。

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

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

    您应该按值获取filename()(和朋友)的返回值(如果类型支持,现代编译器应该会自动表现为移动)。

    注意,MSVC 确实“似乎”接受此代码并“做你期望的”——大概是因为它有一个非标准扩展,即使在绑定时也允许延长临时对象的生命周期到非常量引用。

    【讨论】:

    • 嗯...我很怀疑。 p_name 真的有效吗,因为它是 const 引用?还是因为他在处理pf 而不是p.filename() 而“工作”? (我不提及临时人员,const 或否,所以我想在这里了解细则。)
    • @DevSolar 确实如此:stackoverflow.com/questions/2784262/…(也:GotW #88
    • 谢谢,我意识到我的错误。我在想只要返回值是引用我就可以将它分配给const&amp;;但显然我错了,因为p.filename() 被破坏了。
    • @HongxuChen:根据您的其余代码,将此类优化留给编译器可能具有最少混淆的优点。相当多的 C++ 编码人员还没有完全赶上 C++11,如果编译器“做”C++11,你就会隐式地得到优化。 (我正在做 9 到 5 的三平台可移植代码,所涉及的三个编译器中有两个仍然对 C++11 代码犹豫不决...... :-( )
    • @HongxuChen:只有当你的编译器对于返回值优化(RVO)来说太笨了......
    【解决方案2】:

    不错。 ;-)

    name 是一个参考。即,它仅引用p.filename().string()。然而,这是一个临时的,即它在语句完成后被销毁,留下name 引用无效内存。您在未定义行为国家/地区,很幸运您的程序没有崩溃。

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

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

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

    【讨论】:

    • +1 我断言他不幸程序没有崩溃。再说一次,对于 c++,人们应该永远期望得到幸运。
    猜你喜欢
    • 2011-04-23
    • 2020-06-25
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    相关资源
    最近更新 更多