【发布时间】:2015-08-12 21:12:04
【问题描述】:
我正在尝试围绕 c 头文件 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*) 已读取最后一个文件并且没有更多文件要读取,则返回一个空指针。但是,我不确定如何在不调用m_dirent 上的.reset() 的情况下将dirent 指针设置为dir 指针正在读取的任何内容。但是,这样做只会导致读取垃圾数据,因为我假设文件指针在dirent 被破坏时丢失。
如何转换
while((entry = readdir(dp)))
puts(entry->d_name);
进入现代 C++?
【问题讨论】:
-
一般来说,潜在的问题是您正试图进行从 C 到 C++ 的逐行转换。这不是将基于非 OO、
C的 API 转换为 C++ 接口的最佳方式。您必须查看整体设计,并对其应用适当的模式。举个例子,看看boost是如何实现文件系统API的。 -
查看已被技术报告 2 接受的 Boost.FileSystem (boost.org/doc/libs/release/libs/filesystem)。
-
如果您可以访问 Koenig 的 Ruminations on C++,他的其中一章中有一个例子。但是,这可能不算作现代 C++,因为它比标准早了一年左右,所以它没有从那时起构建的所有经验。
-
@JonathanLeffler:我不知道 Koenig 在目录中有什么东西。你还记得它是如何被曝光的吗?特别是,Koenig 是否将目录公开为迭代器?
-
@DietmarKühl:我需要再次查看代码。 IIRC,有关于使其成为迭代器的讨论,但没有实际这样做的代码。