Суть задачи заключается в поиске файлов и папок по заданным критериям. Использовал паттерн компоновщик.
// path.h
class Path
{
public:
Path();
Path(const std::string&);
~Path();
void setPath(const std::string&);
std::string toString() const;
bool exists() const;
bool isAccess() const;
bool isFile() const;
bool isDirectory() const;
bool isRootDirectory() const;
bool isFullPath() const;
int calculateCountOfObjectsInside(); // Only for directories (object is a file or directory); not includes a directory of "." and ".."
/**
* И ещё множество методов, но не столь важно.
*/
private:
std::string path_;
};
// FileSystemElement.h
class FileSystemElement
{
public:
FileSystemElement(const Path& path);
__time64_t getTimeCreate();
__time64_t getTimeAccess();
__time64_t getTimeWrite();
virtual _fsize_t calculateSize() = 0;
std::string getName();
std::string getPath();
virtual std::vector<FileSystemElement*> search(const std::string& elementName, const std::string& phrase, const bool& recursively) = 0;
protected:
Path path_;
__time64_t timeCreate_; /* -1 for FAT file systems */
__time64_t timeAccess_; /* -1 for FAT file systems */
__time64_t timeWrite_;
_fsize_t size_;
std::string name_;
void initElement(const _finddata_t&);
};
// Directory.h
class Directory : public FileSystemElement
{
public:
Directory(const Path&);
~Directory();
std::vector<FileSystemElement*> getChilds();
std::vector<FileSystemElement*> search(const std::string& elementName, const std::string& phrase, const bool& recursively);
_fsize_t calculateSize();
void reloadChilds();
private:
std::vector<FileSystemElement*> childs_;
bool childsAreInitialized;
void initializeChilds();
};
// File.h
class File : public FileSystemElement
{
public:
File(const Path&);
std::vector<FileSystemElement*> search(const std::string& elementName, const std::string& phrase, const bool& recursively);
_fsize_t calculateSize();
private:
std::string format_;
};
// Метод поиска в file.cpp
std::vector<FileSystemElement*> File::search(const std::string& elementName, const std::string& phrase, const bool& recursively)
{
bool fitsSearchParams = false;
std::string thisFileFormat;
thisFileFormat.append(name_, name_.find(wchar_t('.')) + 1, name_.size());
/**
* Request: "*.[format]"
*/
if (elementName.find('.') != std::string::npos &&
elementName[0] == '*') {
std::string formatFromRequest;
formatFromRequest.append(elementName, elementName.find('.') + 1, elementName.size());
if (thisFileFormat == formatFromRequest)
fitsSearchParams = true;
}
/**
* Request: "*.*"
*/
if (elementName == "*.*")
fitsSearchParams = true;
/**
* Request: "[name].[format]" or "[name]"
*/
if (elementName.find('.') != std::string::npos &&
elementName.find('*') == std::string::npos &&
elementName.find('?') == std::string::npos)
if (name_ == elementName)
fitsSearchParams = true;
if(name_.find(elementName) != std::string::npos)
fitsSearchParams = true;
/**
* Request: "?.[format]"
*/
/**
* Request: "?.?"
*/
/**
* Request: "[name].?"
*/
std::vector<FileSystemElement*> result;
if (fitsSearchParams) {
result.push_back(new File(path_));
}
/**
* Phrase handling.
*/
if (thisFileFormat == "txt" && !phrase.empty())
if (!textFileContainsPhrase(path_, phrase))
fitsSearchParams = false;
return result;
}
bool textFileContainsPhrase(const Path& path, const std::string& phrase)
{
bool fileContainsPhrase = false;
std::ifstream ifs(path.toString().c_str(), std::ifstream::in);
char* str = new char[PHRASE_READING_BUFF_SIZE];
while (!ifs.eof()) {
ifs >> str;
if (std::string(str).find(phrase) != std::string::npos) {
fileContainsPhrase = true;
break;
}
}
ifs.close();
delete[] str;
return fileContainsPhrase;
}
// Поиск в Directory.cpp
std::vector<FileSystemElement*> Directory::search(const std::string& elementName, const std::string& phrase, const bool& recursively)
{
reloadChilds();
std::vector<FileSystemElement*> result;
if (recursively || path_.isRootDirectory())
for (auto child : childs_)
for (auto element : child->search(elementName, phrase, recursively))
result.push_back(element);
if (name_.find(elementName) != std::wstring::npos)
result.push_back(new Directory(path_));
return result;
}
void Directory::reloadChilds()
{
//if(!childs_.empty())
for (auto element : childs_)
delete element;
initializeChilds();
}
void Directory::initializeChilds()
{
if (!childsAreInitialized) {
int nChilds = path_.calculateCountOfObjectsInside();
if (nChilds == 0)
return;
childs_.reserve(path_.calculateCountOfObjectsInside());
std::string find = path_.toString();
find += "\\*";
_finddata_t* data = new _finddata_t;
int handle = _findfirst(find.c_str(), data);
int result = handle;
while (result != -1) {
if (strcmp(data->name, ".") == 0 || strcmp(data->name, "..") == 0) {
result = _findnext(handle, data);
continue;
}
Path internalObject(path_.toString() + '\\' + data->name);
if (internalObject.isFile())
childs_.push_back(new(std::nothrow) File(internalObject));
else
childs_.push_back(new(std::nothrow) Directory(internalObject));
result = _findnext(handle, data);
}
_findclose(handle);
delete data;
childsAreInitialized = true;
}
}
Пограмма падает в методе void Directory::initializeChilds() при втором(не знаю почему именно втором) СТАТИЧЕСКОМ выделении памяти. Падает только когда много уровней вложенности. Писал несколько версий этого метода (заменял динамическим выделением памяти) - всегда одна и та же ошибка на одном и том же объекте файловой системы. Я подовзреваю, что проблема в том, что программа использовала всю выделенную для неё память и поэтому статически уже не резервируется. Ошибка при дебаге
Ошибка при выполнении
Можете помочь, ибо я без понятия как решить эту проблему?
Думал о замене компоновщика на обычную рекурсию. Таким образом не будет объектов классов FileSystemElement*, множества векторов ... Но не хочется уходить с компоновщика и понижать уровень абстракции кода.