Странное поведение push_back () для файловой системы :: path .string (). Data () приводит к «вектору» " - PullRequest
1 голос
/ 13 марта 2020

Запуск этой программы

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

получает

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

Почему не первый элемент argv "ao"?

Я пытаюсь разбить строку А, обнаружив, что когда "bo" - это push_back () в argv, первый элемент argv изменил с "ao" на "bo".

Затем, когда я изменил строку A на

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

Те же результаты.

Когда я изменяю строку A на

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

Внезапно я получаю то, что ожидалось:

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

Может кто-нибудь объяснит странное поведение и разницу между .string (). data () и .c_str ()?

1 Ответ

7 голосов
/ 13 марта 2020

Проблема в том, что функция 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 вектор или время жизни вектора (и содержащийся в нем объект) (когда вектор разрушен).

Обратите внимание, что если вы Если вы используете oop, например

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

, где p является копией path объектов, то у вас будет такая же проблема даже с p.c_str(), как и у объекта p закончит свою жизнь и будет уничтожен в конце каждой итерации l oop.

...