gpt4 book ai didi

c++ - 围绕 C Dirent.h 的现代 C++ 包装器

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:38:45 26 4
gpt4 key购买 nike

我正在尝试围绕 c header dirent.h 编写一个现代 c++ 包装器。

在C中要读取一个目录的内容,写成类似下面的内容:

int listdir(const char *path) {
struct dirent *entry;
DIR *dp;

dp = opendir(path);
if (dp == NULL) {
perror("opendir");
return -1;
}

while((entry = readdir(dp)))
puts(entry->d_name);

closedir(dp);
return 0;
}

将其转换为现代 C++,我有以下内容(其中 m_dir 和 m_dirent 是 std::unique_ptr 的,而 m_files 是 std::vector<string> )

filesystem::Directory::Directory(std::string dir) : m_dir(opendir(dir.c_str()), closedir),
m_dirent(new struct dirent())
{
//If the directory can not be read, throw an error.
if (!m_dir) {
sdl2::SDLFileSystemRead_Failure ex;
throw ex;
}

while (&(*m_dirent = *readdir(&*m_dir)))
{

m_files.emplace_back(std::string(m_dirent->d_name));

}

}

这只成功了一半。当我写它的时候,我没有注意到我只是在检查表达式的地址 *m_dirent = *readdir(&*m_dir)存在(当然它确实存在!)。根据The Single UNIX ® Specification, Version 2 , readdir(DIR*) 如果它已经读取了最后一个文件并且没有更多的文件要读取,则返回一个空指针。但是,我不确定如何在不调用 .reset() 的情况下将 dirent 指针设置为 dir 指针正在读取的内容。在 m_dirent .但是,这样做只会导致读取垃圾数据,因为我假设文件指针在 dirent 时丢失了。被摧毁。

我如何转换它

  while((entry = readdir(dp)))
puts(entry->d_name);

进入现代 C++?

最佳答案

我不确定这算不算是现代,因为我在上个千年在 UseNet 上发布了类似的内容(here 是精炼版)。它略有进化,成为最早用于播种的成分之一 Boost 1998 年。由于其他人的工作,它在 Boost 得到了进一步发展,并最终变成了 file system library。这构成了File System TS的基础.

然而,这一切都始于一个简单的想法:如何很好地公开 opendir()readdir()closedir() ?有点明显的答案是:使用迭代器!这是一个简单的版本和演示:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <stdexcept>
#include <memory>
#include <dirent.h>

class dir_it
: public std::iterator<std::input_iterator_tag, std::string>
{
std::shared_ptr<DIR> dir;
std::string current;
void advance() {
dirent entry;
dirent* result;
if (!readdir_r(dir.get(), &entry, &result) && result) {
this->current = result->d_name;
}
else {
this->dir.reset();
}
}
public:
dir_it(std::string const& path)
: dir(opendir(path.c_str()), [](DIR* dir){ dir && closedir(dir); }) {
if (!dir) {
throw std::runtime_error("failed to open directory '" + path + "'");
}
this->advance();
}
dir_it(): dir() {}

std::string const& operator*() const { return this->current; }
dir_it& operator++() { this->advance(); return *this; }
dir_it operator++(int) {
dir_it rc(*this);
this->operator++();
return rc;
}
bool operator==(dir_it const& other) const {
return bool(this->dir) == bool(other.dir);
}
bool operator!=(dir_it const& other) const {
return !(*this == other);
}
};

int main() {
std::copy(dir_it("."), dir_it(), std::ostream_iterator<std::string>(std::cout, "\n"));
}

当然,Boost 和文件系统 TS 中的文件系统库比这个有点幼稚的实现更强大。如果您的实现附带了 TS 的实现,我会使用它。如果不是,您可能需要考虑 Boost 的实现。

关于c++ - 围绕 C Dirent.h 的现代 C++ 包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31975501/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com