Am I using std::unique_ptr the wrong way?
Aug 16, 2014 at 6:24am UTC
I'm using gcc-4.9.1 to compile this code that list the contents of directories recursively. I tried to wrap the DIR ptr in a unique_ptr but then it doesn't compile. In clang it throws this error:
/usr/include//c++/4.9.1/tuple:172:13: error: data member instantiated with function type 'int (__dirstream *)'
_Head _M_head_impl;
...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
// listdir_recursive.c
// Osmar D. G
// Imprime el contenide de un directorio de manera recursiva
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <cstdlib>
#include <cerrno>
#include <memory>
namespace {
using dirent_entry = struct dirent;
//using file_status = struct stat;
constexpr const char * pwd="." ;
constexpr const char * parent_dir=".." ;
class file_status {
public :
file_status()=default ;
explicit file_status(std::string file_name): file_name_{file_name} {
init();
}
bool is_directory() { return (stat_buf_.st_mode & S_IFMT)==S_IFDIR; }
bool is_equal(const char * dirname) { return file_name_.compare(dirname)==0;}
private :
void init(){ lstat(file_name_.c_str(), &stat_buf_); }
std::string file_name_;
struct stat stat_buf_;
};
auto list_directory(std::string dir, const size_t tab_size=0)->void {
dirent_entry * entry;
// cambiar por std::unique_ptr
//auto dirptr = opendir(dir.c_str());
std::unique_ptr<DIR, decltype (closedir)> dirptr(opendir(dir.c_str()), closedir);
if (dirptr==nullptr ){
std::cerr << "No se pudo abrir el directorio...\n" ;
exit(errno);
}
//Nos vamos al directorio
chdir(dir.c_str());
std::string tab (tab_size, ' ' );
while ( (entry=readdir(dirptr.get())) not_eq nullptr ) {
file_status stats{entry->d_name};
if (stats.is_directory()){
if (stats.is_equal(pwd) or stats.is_equal(parent_dir))
continue ;
std::cout << tab << entry->d_name << std::endl;
list_directory(entry->d_name, tab_size+2);
}
std::cout << tab << entry->d_name << std::endl;
}
chdir(parent_dir);
//closedir(dirptr);
}
}
int main(int argc, char ** argv){
using namespace std::literals::string_literals;
const char * top_dir = nullptr ;
if (argc not_eq 2)
top_dir = pwd;
else
top_dir=argv[1];
std::cout << "Scaneando el directorio: " s + top_dir + "\n" s << std::flush;
list_directory(top_dir);
std::cout << "listo....." << std::endl;
}
Aug 16, 2014 at 7:30am UTC
Workaround
a. Modify
1 2
// std::unique_ptr<DIR, decltype(closedir)> dirptr(opendir(dir.c_str()), closedir);
std::unique_ptr< DIR, std::function< int (DIR*) > > dirptr( opendir(dir.c_str()), closedir ); // ***
b. Compile with
-std=c++1y
http://coliru.stacked-crooked.com/a/c24e2c0d114add0a
Aug 16, 2014 at 5:02pm UTC
Yep, that worked.. thanks. But innit decltype(closedir) and std::function<int(DIR*)> semantically the same?
Aug 16, 2014 at 5:46pm UTC
Semantically, they are akin to each other.
Syntactically, they are not.
The type
decltype(closedir) is function (
int( DIR* ) ).
The type
std::function<int(DIR*)> is function object.
The type
decltype( &closedir ) is pointer to function. This works.
http://coliru.stacked-crooked.com/a/8d915aa9d131fbcc
The type
decltype( (closedir) ) is lvalue reference to function. This too works.
http://coliru.stacked-crooked.com/a/70afcfef0d74d477
The default type for the template parameter D is default_delete.
A client-supplied template argument D shall be a function object type, lvalue-reference to function, or lvalue-reference to function object type for which ... <elided> ... - IS
-std=c++1y is a work-around; with
-std=c++11 , the GNU library on linux appears to be broken.
Aug 16, 2014 at 6:49pm UTC
I get it now. That is why clang was giving this: error: data member instantiated with function type 'int (__dirstream *)' . Thank you very much!
Topic archived. No new replies allowed.