Есть ли уже реализованный дескриптор файла RAII?

Дескриптор файла RAII выглядит довольно просто, так что, я думаю, он уже реализован? Но я не нашел никакой реализации. Я нашел file_descriptor в boost::iostreams, но не знаю, то ли это, что я ищу.


person valentin    schedule 01.04.2014    source источник
comment
Дескрипторы файлов слишком старомодны для C, чтобы привлекать внимание гуру C++. Хотя я с тобой.   -  person Mark Ransom    schedule 01.04.2014
comment
Вы не смогли найти std::fstream?   -  person DevSolar    schedule 01.04.2014
comment
Дескрипторы файлов @MarkRansom являются примитивами ОС, а не вещами C в старом стиле.   -  person Dev Null    schedule 22.10.2017
comment
@DevNull для меня дескриптор файла означает FILE*. Что это значит для вас?   -  person Mark Ransom    schedule 22.10.2017
comment
@MarkRansom также может означать дескриптор файла, как в man7.org/linux /man-pages/man2/open.2.html или HANDLE, как в msdn.microsoft.com/en-us/library/windows/desktop/   -  person Dev Null    schedule 22.10.2017


Ответы (3)


std::fstreams поддерживают использование в стиле RAII — их можно открыть и даже протестировать при построении, и они автоматически сбрасываются и закрываются в деструкторе, хотя вы можете пропустить ошибки, если просто предполагаете, что это работает, поэтому вы можете захотеть сделать что-то более явное в код, если вам нужна надежность.

Например:

if (std::ifstream input(filename))
    ... use input...
else
    std::cerr << "unable to open '" << filename << "'\n";

Если вы действительно хотите использовать файловые дескрипторы, вы можете настроить что-то вроде следующего по вкусу. Это немного длиннее, чем то, что просто вызывает close, но если вы хотите сделать надежное программирование, вам нужно как-то проверять и обрабатывать ошибки....

struct Descriptor
{
    Descriptor(int fd, const char* filename = nullptr)
      : fd_(fd), filename_(filename)
    {
        if (fd < 0)
        {
            std::ostringstream oss;
            oss << "failed to open file";
            if (filename_) oss << " '" << filename_ << '\'';
            oss << ": " << strerror(errno);
            throw std::runtime_error(oss.str());
        }
    }
    ~Descriptor()
    {
        if (fd_ != -1 && close(fd_) == -1)
        {
            // throwing from destructors risks termination - avoid...
            std::cerr << "failed to close file";
            if (filename_) std::cerr << " '" << filename_ << '\'';
            std::cerr << ": " << strerror(errno) << std::endl;
        }
    }
    operator int() const { return fd_; }

  private:
    int fd_;
};

Применение:

try
{
    Descriptor fd(open(filename, O_RDONLY), filename);
    int nbytes = read(fd, ...);
    ...
}
catch ...
person Tony Delroy    schedule 01.04.2014

Зависит от того, что именно вы хотите.

Если вам действительно нужен дескриптор с областью действия, используйте:

std::unique_ptr<HANDLETYPE, closehandletypefunction> smartpointer;

Для указателей FILE это будет выглядеть так

std::unique_ptr<FILE, int (*)(FILE *)> f(fopen("myfile.txt", "a"), fclose);

Затем FILE* можно получить с помощью f.get(). То же самое будет работать с файловыми дескрипторами (open и close из <fcntl.h> и <unistd.h> соответственно).

Тем не менее, предпочтительный способ C++ - это оборачивать дескриптор в объект с тысячами членов, чтобы делать все.

person Deduplicator    schedule 01.04.2014

Я использую boost::filesystem::ifstream (или ofstream для письма).

На самом деле я спрашивал об этом, потому что хотел быть уверенным, что мой файл был закрыт, даже если перед вызовом file.close() возникло исключение.

Но после прочтения документации еще раз:

В случае уничтожения объекта, все еще связанного с открытым файлом, деструктор автоматически вызывает функцию-член close.

Так что это безопасно :)

person valentin    schedule 01.04.2014