push_back() a filesystem::path's .string().data() 的奇怪行为导致“vector<const char *>”

use*_*835 1 c++ string vector char std-filesystem

运行这个程序

#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;
}
Run Code Online (Sandbox Code Playgroud)

得到

b.o
b.o
a.o
b.o
Run Code Online (Sandbox Code Playgroud)

为什么 argv 的第一个元素不是“ao”?

我尝试在A线断,找出当“博”是的push_back()插入的argv,argv的的第一个元素改变从“AO”到“博”。

然后,当我将 A 行更改为

        argv.push_back(p.string().c_str()); // line A: .string().data() -> .string().c_str()
Run Code Online (Sandbox Code Playgroud)

结果一样。

当我将 A 行更改为

        argv.push_back(p.c_str()); // line A: .string().data() -> .c_str()
Run Code Online (Sandbox Code Playgroud)

突然,我得到了预期的结果:

a.o
b.o
a.o
b.o
Run Code Online (Sandbox Code Playgroud)

有人可以解释奇怪的行为以及 .string().data() 和 .c_str() 之间的区别吗?

Som*_*ude 7

问题是path::string()函数按值返回字符串。

一个将在表达式结束后立即销毁的p.string().data()

这意味着指针将立即无效,并且当您尝试取消引用它时(例如打印时),您将有未定义的行为

显而易见的解决方案是不对char*字符串使用向量,而是使用向量std::string


至于使用p.string().data()(或p.string().c_str()) 和之间的区别p.c_str(),在于p.c_str()返回一个指向path由 引用的对象内部的内部字符串的指针p。该path对象将不会被破坏,直到任一clear所述的载体或载体的寿命时间(及其包含的对象)的端部(当载体被破坏)。

请注意,如果您使用了循环,例如

for (auto p : paths) { ... }
Run Code Online (Sandbox Code Playgroud)

whereppath对象的副本,那么即使使用p.c_str(),您也会遇到相同的问题,因为对象p将结束其生命周期并在循环的每次迭代结束时被销毁。