Вопрос

Я прочитал статью о защитных устройствах (Общий:Измените способ написания безопасного к исключениям кода — навсегда) в DDJ, и я понимаю их общее использование.

Однако обычно используется создание экземпляра конкретного средства защиты стека в стеке для конкретной операции, например:

{
    FILE* topSecret = fopen("cia.txt");
    ON_BLOCK_EXIT(std::fclose, topSecret);
    ... use topSecret ...
} // topSecret automagically closed

но что, если я хочу запланировать операции очистки во время выполнения, напримеркогда у меня есть цикл:

{
   vector<FILE*> topSecretFiles;
   for (int i=0; i<numberOfFiles; ++i)
   {
      char filename[256];
      sprintf(filename, "cia%d.txt", i);
      FILE* topSecret = fopen(filename);
      topSecretFiles.push_back(topSecret);
      ON_BLOCK_EXIT(std::fclose, topSecret); // no good
   }
}

Очевидно, что приведенный выше пример не будет работать, поскольку topSecret будет закрыто вместе с для объем.Мне нужен шаблон защиты области, в котором я мог бы так же легко ставить в очередь операции очистки, которые, по моему мнению, необходимы. во время выполнения.Есть ли что-то подобное в наличии?

Я не могу поместить объекты защиты области в стандартную очередь, потому что исходный объект (тот, который я помещаю) будет отклонен в процессе.Как насчет включения защиты стека, выделенной в куче, и использования очереди, которая удаляет ее члены в dtor?Есть ли у кого-нибудь более умный подход?

Это было полезно?

Решение

Кажется, вы не цените RAII таким, какой он есть.Эти охранники области иногда хороши для локальных («областей») вещей, но вам следует стараться избегать их в пользу того, что на самом деле должен делать RAII:инкапсуляция ресурса в объект.Тип FILE* на самом деле просто не годится для этого.

Вот альтернатива:

void foo() {
    typedef std::tr1::shared_ptr<FILE> file_sptr;
    vector<file_sptr> bar;
    for (...) {
        file_sptr fsp ( std::fopen(...), std::fclose );
        bar.push_back(fsp);
    }
}

Или:

void foo() {
    typedef std::tr1::shared_ptr<std::fstream> stream_sptr;
    vector<stream_sptr> bar;
    for (...) {
        file_sptr fsp ( new std::fstream(...) );
        bar.push_back(fsp);
    }
}

Или в «C++0x» (будущий стандарт C++):

void foo() {
    vector<std::fstream> bar;
    for (...) {
        // streams will become "movable"
        bar.push_back( std::fstream(...) );
    }
}

Редактировать:Поскольку мне очень нравятся подвижные типы в C++0x и вы проявили к ним интерес:Вот как вы можете использовать unique_ptr в сочетании с FILE* без каких-либо накладных расходов на подсчет ссылок:

struct file_closer {
    void operator()(FILE* f) const { if (f) std::fclose(f); }
};

typedef std::unique_ptr<FILE,file_closer> file_handle;

file_handle source() {
    file_handle fh ( std::fopen(...) );
    return fh;
}

int sink(file_handle fh) {
    return std::fgetc( fh.get() );
}

int main() {
    return sink( source() );
}

(непроверено)

Обязательно проверьте Блог Дэйва об эффективных типах перемещаемых значений

Другие советы

Да, оказывается, защита области DDJ «подвижна», не в смысле C++0x, а в том же смысле, в котором auto_ptr является подвижным:во время копирования новый охранник «увольняет» старого охранника (например, копирующий фактор auto_ptr вызывает старого auto_ptr::release).

Поэтому я могу просто сохранить queue<ScopeGuard> и это сработает:

queue<ScopeGuard> scopeGuards;

// ...

for (...)
{
   // the temporary scopeguard is being neutralized when copied into the queue,
   // so it won't cause a double call of cleanupFunc
   scopeGuards.push_back(MakeScopeGuard(cleanupFunc, arg1));
   // ...
}

Кстати, спасибо за ответ выше.Для меня это было познавательно и познавательно по-разному.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top