Как реализовать RAII + ленивая инициализация?

Можно ли реализовать в C ++ дизайн, который одновременно
— RAII, чтобы обеспечить безопасное освобождение ресурса, и
— ленивая инициализация, что ресурс приобретается только тогда, когда он действительно используется.

Моя идея состоит в том, чтобы просто реализовать как ленивую инициализацию, в то время как в реальном сборе ресурсов, используйте RAII.

Как отраслевая практика?

-1

Решение

Да, это возможно. Просто используйте std::optional (C ++ 17 или из Увеличение) или же unique_ptr/shared_ptr.

(Мнение) optional имеет большое преимущество в удобочитаемости — вы не можете быть более ясным, что это значение не может быть инициализировано.

Чтобы показать, что ресурсы высвобождаются правильно: сначала давайте начнем с нетерпеливой инициализации (жить):

ofstream file("test.txt");
file << "no flush\n";

ifstream inFile("test.txt");
string line;
getline(inFile, line);
cout << line << endl;

Это, ничего не печатает для меня ». Давайте переместим запись в отдельную область (жить):

{
ofstream file("test.txt");
file << "no flush\n";
}

ifstream inFile("test.txt");
string line;
getline(inFile, line);
cout << line << endl;

Это должно напечатать no flush, так как ofstream гарантировано close() файл при уничтожении. (если к чему-то еще test.txt в то же время)

А теперь с Boost.Optional и ленивым init (жить):

{
boost::optional<std::ofstream> file;

file = ofstream("test.txt");
file.get() << "no flush\n";
}

ifstream inFile("test.txt");
string line;
getline(inFile, line);
cout << line << endl;

Ресурсы высвобождаются одновременно с обычными ofstream,

Access доступ к файлам не гарантированно буферизуется, но это хороший пример, также доступный в онлайн-компиляторах.

2

Другие решения

Обычная практика — избегать ленивой инициализации, где это возможно.

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

Чтобы справиться с этим, реализация объекта (или класса) должна отслеживать, действительно ли объект инициализирован или нет. Это делает реализацию класса более сложной — если ЛЮБАЯ функция-член забывает проверить, инициализирован ли объект, или если какая-либо функция-член переводит объект в недопустимое состояние, может возникнуть хаос. Если объект (или класс) этого не делает, класс труднее использовать, потому что любая ошибка в коде, который использует класс, вызывает проблемы.

Вместо этого чаще используется метод, который заключается в том, что (1) конструкторы устанавливают инвариант (2) функции-члены, предполагающие, что инвариант и (3) деструкторы очищаются.

Другими словами, конструкторы инициализируют объект, а функции-члены гарантируют, что объект остается в разумном состоянии. Функции-члены могут предполагать, что объект находится в действительном состоянии, когда они вызываются …. поэтому проверять не нужно. Пока все функции-члены гарантируют, что объект все еще находится в действительном состоянии, когда они возвращаются, проблем нет.

Единственным исключением является деструктор, который заставляет объект перестать существовать. Другими словами, после уничтожения объекта (вызова его деструктора) никакие члены этого объекта не должны использоваться вообще.

Для вызывающего это просто — не создавайте объект, пока не появится информация, необходимая для его создания. Другими словами, вместо

 SomeObject object;

// gather data needed to initialise object

//   Danger, danger: it is possible to mistakenly use object as if it is initialised here

object.initialise(needed_data);

// do other things with object

//object ceases to exist (e.g. end of {} block).

сделай это

 // gather data needed to initialise object

//   note that the compiler will reject using object here

SomeObject object(needed_data);

// do other things with object

//object ceases to exist (e.g. end of {} block).

В C ++ нет ничего, препятствующего созданию объекта, когда он необходим. Переменные не ограничиваются объявлением в верхней части блока или чем-то подобным.

1

По вопросам рекламы [email protected]