C++ 现代C++;围绕C Dirent.h的包装
我试图围绕C标题写一个现代C++包装,dio.H. 要在C中读取目录的内容,需要编写如下内容:C++ 现代C++;围绕C Dirent.h的包装,c++,pointers,c++11,C++,Pointers,C++11,我试图围绕C标题写一个现代C++包装,dio.H. 要在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->
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++,我有如下(其中Mydir和MydiRoad是*m_dirent=*readdir(&*m_dir)
的地址是否存在(当然它确实存在!)。
根据,如果readdir(DIR*)已读取最后一个文件,并且没有更多的文件要读取,则返回空指针。但是,我不确定如何在不调用m\u dirent
上的.reset()
的情况下将dirent指针设置为dir指针正在读取的内容。但是,这样做只会导致读取垃圾数据,因为我假设当dirent
被销毁时,文件指针会丢失
我如何转换这个
while((entry = readdir(dp)))
puts(entry->d_name);
<现代C++ >?p> 逗号运算符来营救
while(entry.reset(readdir(m_dir.get())), entry)
puts(entry->d_name);
虽然,正如评论所说,对于文件系统来说,这不是一个奇妙的API。例如,透明地适应底层目录的迭代器会很酷。我不确定这个计数是否像我在上个千年的UseNet中发布的那样现代(是一个改进版)。它稍微进化,成为1998年用于播种的首批成分之一。多亏了其他人的努力,它在Boost得到了进一步发展,并最终成为了一个新的平台,它构成了 然而,这一切都是从一个简单的想法开始的:如何很好地公开
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"));
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
类dir_it
:public std::迭代器
{
std::共享目录;
串电流;
作废预付款(){
直接进入;
直接结果;
if(!readdir_r(dir.get(),&entry,&result)&&result){
此->当前=结果->数据单元名称;
}
否则{
此->目录重置();
}
}
公众:
dir_it(标准::字符串常量和路径)
:dir(opendir(path.c_str()),[](dir*dir){dir&&closedir(dir);}){
如果(!dir){
抛出std::runtime_错误(“未能打开目录“”+path+”);
}
这个->前进();
}
dir_it():dir(){}
std::字符串常量和运算符*()常量{返回此->当前;}
dir_it&operator++(){this->advance();return*this;}
dir_it运算符++(int){
dir_it rc(*本);
这个->操作符++();
返回rc;
}
布尔运算符==(dir_it const和其他)const{
返回bool(this->dir)==bool(other.dir);
}
布尔运算符!=(dir_it const和其他)const{
返回!(*此==其他);
}
};
int main(){
std::copy(dir_it(“.”),dir_it(),std::ostream_迭代器(std::cout,“\n”);
}
当然,Boost和文件系统TS中的文件系统库比这个有点幼稚的实现功能更强。如果您的实现附带了TS的实现,我会使用它。如果C++不需要考虑Boost的实现。一般来说,下面的问题是你试图逐行逐行地从C到C++进行转换。这不是将非OO、<代码> C/<代码> API转化为C++接口的最佳方法。您必须查看整体设计,并对其应用适当的模式。例如,看看
boost
是如何实现文件系统API的。看看boost.filesystem(),它已被技术报告2接受。如果您可以访问Koenig的,他在他的一章中有一个例子。然而,这可能不算是现代C++,因为它早于标准一年左右,所以它没有任何经验,因为它建立。@ JoaNahan-Leffffel:我不知道凯尼格有一些目录上的东西。你还记得它是怎么暴露出来的吗?特别是,Koenig是否将目录公开为迭代器?@DietmarKühl:我需要再次查看代码。IIRC曾讨论过如何使其成为一个迭代器,但实际上并没有这样做的代码。
#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"));
}