Данные внутри вектора C++ изменяются, когда я использую push_back()

Я написал функцию C++, которая использует «recursive_directory_iterator» для получения информации обо всех файлах и папках в родительской папке. Затем я написал класс DataFolder для хранения атрибутов каждого файла, таких как размер файла, путь, имя, дата и т. д. Наконец, я использовал векторный объект для хранения коллекции объектов DataFolder.

Для векторного объекта я использую push_back для добавления объектов DataFolder. Первое назначение работает, однако при последующих попытках назначения выполняются без проблем с памятью или доступом, но данные, содержащиеся во всех ранее сохраненных элементах, повреждаются. Только самое последнее добавление остается без изменений.

Как добавить объекты DataFolder в мой векторный объект C++ STL и сохранить данные, ранее хранившиеся в векторе?

Это функция, которую я создал: Directory_base.

#include <iostream>
#include <filesystem>
#include <ctime>
#include <vector>
#include "CDir.h"

using namespace std;
using namespace std::filesystem;

// CDIR List folder.
// CDIR NAME lists the files in a folder.NAME must be specified as a
// character vector or string scalar.
//
// NAME can include a relative path, but the relative path must be in the
// current folder.Otherwise, NAME must include a full path.
//
// To list filesand folders at a remote location, NAME must contain a
// full path specified as a uniform resource locator(URL).
//
// Pathnamesand asterisk wildcards may be used in NAME.A single asterisk
// in the path touching only file separators will represent exactly one
// folder name.A single asterisk at the end of an input will represent
// any filename.An asterisk followed or preceded by characters will
// resolve to zero or more characters.A double asterisk can only be used
// in the path and will represent zero or more folder names.It cannot
// touch a character other than a file separator.For example, DIR* .m
// lists all files with a.m extension in the current folder.DIR*/*.m
//   lists all files with a .m extension exactly one folder under the
//   current folder. CDIR **/* .m lists all files with a.m extension zero or
// more folders under the current folder.
//
// D = CDIR('NAME') returns the results in an M - by - 1
// structure with the fields :
// name        -- Filename
// folder      -- Absolute path
// date        -- Modification date
// bytes       -- Number of bytes allocated to the file
// isdir-- 1 if name is a folder and 0 if not
// datenum     -- Modification date as a MATLAB serial date number.
// This value is locale - dependent.
//
// See also WHAT, CD, TYPE, DELETE, LS, RMDIR, MKDIR, DATENUM.

// Copyright 1984 - 2019 The MathWorks, Inc.
// Built - in function.

static const char* convertIntToMonth(int imon)
{
    if (imon == 1)
    {
        return "Jan";
    }
    else if (imon == 2)
    {
        return "Feb";
    }
    else if (imon == 3)
    {
        return "Mar";
    }
    else if (imon == 4)
    {
        return "Apr";
    }
    else if (imon == 5)
    {
        return "May";
    }
    else if (imon == 6)
    {
        return "Jun";
    }
    else if (imon == 7)
    {
        return "Jul";
    }
    else if (imon == 8)
    {
        return "Aug";
    }
    else if (imon == 9)
    {
        return "Sep";
    }
    else if (imon == 10)
    {
        return "Oct";
    }
    else if (imon == 11)
    {
        return "Nov";
    }
    else if (imon == 12)
    {
        return "Dec";
    }
    else if (imon < 1 || imon > 12)
    {
        return "OOR";
    }

    return "INV";
}

static double dateNumber(double year, int month, double day)
{
    double cumdays[] = { 0, 0,31,59,90,120,151,181,212,243,273,304,334 };
    double retval = 365 * year + cumdays[month] + day;
    retval += year / 4;
    return retval;
}

const vector<DataFolder>& directory_base(const char* path, vector<DataFolder>& datfldr)
{
    int ii = 0;
    
    cout << "Let put out the files!" << endl;
    for (recursive_directory_iterator i(path), end; i != end; ++i)
    {
        if (!is_directory(i->path()))
        {
            if (is_regular_file(i->path()))
            {
                DataFolder df{};
                filesystem::path df_name = i->path();
                string fn = df_name.string();
                df.name = new char[fn.length()];
                df.name = const_cast<char*>(fn.c_str());
                struct stat attrib {};
                struct tm *clock = new tm();
                stat(df.name, &attrib);
                errno_t errNo = localtime_s(clock, &(attrib.st_mtime));
                size_t fsz = file_size(df.name);
                df.bytes = static_cast<int>(file_size(df_name));
                
                string tmp = to_string(clock->tm_mday) + "-" + 
                convertIntToMonth(clock->tm_mon+1) + "-" + to_string(clock->tm_year+1900) + " 
                " + to_string(clock->tm_hour) + ":" + to_string(clock->tm_min) + ":" + 
                to_string(clock->tm_sec);

                df.date = new char[tmp.length()];
                df.date = const_cast<char*>(tmp.c_str());
                
                df.datenum = dateNumber(static_cast<double>(clock->tm_year)+1900, clock-
                >tm_mon+1, clock->tm_mday);

                filesystem::path df_fldr = i->path().parent_path();
                string ffldr = df_fldr.string();
                df.folder = new char[ffldr.length()];
                df.folder = const_cast<char*>(ffldr.c_str());
                df.isdir = false;
                
                cout << i->path().filename() << "\n";
                
                cout << "\nData Folder Values" << endl;
                cout << "df.name:       " << df.name << endl;
                cout << "df.date:       " << df.date << endl;
                cout << "df.bytes:      " << df.bytes << endl;
                cout << "df.datenum:    " << df.datenum << endl;
                cout << "df.folder:     " << df.folder << endl;
                cout << "df.df.isdir:   " << df.isdir << endl;
                datfldr.push_back(df);
            }
        }
    }

    return datfldr;
}

Я ожидаю, что данные будут выглядеть так:

ожидаемый результат хранения папки данных

Вместо этого я получил это:

Фактический результат хранения папки данных

Спасибо за ваше время и помощь.

Вы выполняете кучу ручных операций по управлению памятью в DataFolder и нарушаете принцип инкапсуляции, делая это вне класса. Возможно, это нарушение Правила трёх, в зависимости от того, удаляет ли этот класс свою память в деструкторе. Могут быть и другие проблемы. Вы должны показать, как реализован этот класс.

paddy 23.05.2024 07:22

Проблема здесь, скорее всего, в том, как вы справляетесь с df.folder. Вы выделяете массив символов и присваиваете его df.folder, затем в следующей строке берете указатель из ffldr и сохраняете его в df.folder. Это приводит к утечке вашего new, И это означает, что df.folder указывает на содержимое стека, которое испарится.

Tim Roberts 23.05.2024 07:24

Как указано выше (проклятие!). Вы начинаете с выделения памяти, которая слишком мала для хранения этих строк, что само по себе является проблемой. Но затем слейте их, заменив указатель на временный. Это действительно катастрофа. Это не способ копирования строк. Вы должны выделить достаточно места, чтобы включить нулевой терминатор, а затем использовать strncpy. Почему вы не сохраняете участников std::string в своем классе? Если бы вы это сделали, все эти проблемы исчезли бы.

paddy 23.05.2024 07:24

Прочитайте это stackoverflow.com/questions/72330113/…

n. m. could be an AI 23.05.2024 07:31
df.name = new char[fn.length()]; -- Это старая ошибка «в библиотеке используются указатели, поэтому позвольте мне съехать с обрыва и использовать указатели на». Как уже упоминалось, ваш класс DataFolder должен использовать std::string. Тот факт, что внутренняя библиотека предоставляет char *, не означает, что ваши собственные классы должны последовать этому примеру и делать то же самое.
PaulMcKenzie 23.05.2024 09:08

Это ужасная смесь неправильного C и C++. Вам вообще не нужны указатели. Вам не нужно изобретать велосипед. Используйте std::string,std::filesystem::path, std::chrono::year_month_day... И почти все ваши проблемы исчезнут. Использование указателей требует высокого профессионализма и особых проблем.

Red.Wave 23.05.2024 12:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
6
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в этих трех строках:

string ffldr = df_fldr.string();
df.folder = new char[ffldr.length()];
df.folder = const_cast<char*>(ffldr.c_str());

Первая строка создает локальный объект, который выйдет за пределы области видимости и будет уничтожен после завершения блока if (is_regular_file(i->path())).

Вторая строка выделяет память для строки из ffldr.length() минус один символов, поскольку массивам строковых символов в стиле C требуется место для символа с нулевым завершающим элементом.

Третья строка перезаписывает только что созданный указатель, теряя выделенную память. Указатель также станет недействительным, как только блок закончится и время жизни ffldr закончится.

Естественное решение C++ — это, конечно, создать DataFolder::folder a std::string.

Если по какой-то причине этого не может быть, сначала нужно выделить символы ffldr.length() + 1 и использовать std::strcpy для копирования строки.

df.name = new char[fn.length()]; df.name = const_cast<char*>(fn.c_str()); использует тот же неверный шаблон несколькими строками выше.
Retired Ninja 23.05.2024 07:41

Когда const_cast попадает в программу, это обычно является ярким индикатором того, что вот-вот произойдет что-то плохое. Не всегда, но я бы сказал, что почти в 100% случаев, когда он написан кем-то без нескольких лет опыта работы с C++.

paddy 23.05.2024 07:46

@paddy Я удалил это. Использование std::strcpy для копирования строки сейчас.

BiggerB2008 23.05.2024 22:49

@RetiredNinja Я исправил все шаблоны, в которых использовался этот код.

BiggerB2008 23.05.2024 22:51

@Какой-то чувак-программист использовал std::strcpy и выделил ffldr.length()+1 байт в df.folder.

BiggerB2008 23.05.2024 22:54

Другие вопросы по теме