1

Running this program

#include <iostream>
#include <filesystem>
#include <vector>

using namespace std;
namespace fs = filesystem;

int main() {
    vector<fs::path> paths{"a.o", "b.o"};

    vector<const char *> argv{};
    for (auto &p : paths) {
        argv.push_back(p.string().data()); // line A
    }
    argv.push_back(paths[0].string().data());
    argv.push_back(paths[1].string().data());

    for (auto &s : argv) {
        cout << s << endl;
    }

    return 0;
}

gets

b.o
b.o
a.o
b.o

Why isn't the first element of argv "a.o"?

I try to break at line A, finding out that when "b.o" is push_back() into argv, the first element of argv changed from "a.o" to "b.o".

Then, when I change line A to

        argv.push_back(p.string().c_str()); // line A: .string().data() -> .string().c_str()

Same results.

When I change line A to

        argv.push_back(p.c_str()); // line A: .string().data() -> .c_str()

Suddenly I get what expected:

a.o
b.o
a.o
b.o

Can someone explain the weird behavior and the difference between .string().data() and .c_str()?

1 Answers1

7

The problem is that the path::string() function returns the string by value.

A value which will be destructed as soon as the expression p.string().data() ends.

That means the pointer will become immediately invalid and you will have undefined behavior when you try to dereference it (for example when printing it).

The obvious solution is to not use vectors of char* for strings, but vector of std::string instead.


As for the difference between using p.string().data() (or p.string().c_str()) and p.c_str(), it's that p.c_str() returns a pointer to the internal string inside the path object referenced by p. That path object will not be destructed until you either clear the vector or the life-time of the vector (and its contained object) ends (when the vector is destructed).

Note that if you used a loop such as

for (auto p : paths) { ... }

where p is a copy of the path objects, then you would have the same problem even with p.c_str(), as then the object p would end its life and be destructed at the end of each iteration of the loop.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621