Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

string

boost

There seem some strange behaviors for pf.string() output, where pf is generated with p.filename(), where p is of type boost::filesystem::path and constructed with char const* or std::string.

Here is the code segment:

#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;
}

The argv[0] here is fs.out and the output of the executable(compiled with clang3.4/ gcc4.9 with -O3/-O0) is:

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

The boost version I used is 1.55 from Debian jessie(testing) package.

My questions:

  • Why name is empty in the first 2 lines?
  • Why p_name is not empty but name is empty at Line 2?
  • Why this program has the correct(?) output at Line 3 although it seems that there is no relationship between s_name and name?
like image 485
Hongxu Chen Avatar asked Mar 19 '23 12:03

Hongxu Chen


1 Answers

You're taking references to temporaries.

Iff bound to a const reference (like p_name) the lifetime of the temporary will be extended to the end of the containing scope.

Otherwise you're simply invoking Undefined Behaviour. This also explains how name changes when you assign to a totally different variable. This apparently happens because s_name happens to allocate the same memory chunk that name still (erronously!) refers to. Much worse things might happen.

You should take the return values of filename() (and friends) by value (which should on modern compilers automatically behave as a move if the type supports that).

Note that MSVC does "appear" to accept this code and "do what you expect" - presumably because it has a non-standard extension that allows the lifetime of temporaries to be extended even when bound to non-const references.

like image 194
sehe Avatar answered Mar 31 '23 16:03

sehe