C ++ RAII Вопросы - PullRequest
       13

C ++ RAII Вопросы

10 голосов
/ 26 сентября 2011

Итак, насколько я понимаю, для правильной реализации RAII, если я буду вызывать CreateFont, я оберну это в класс с CreateFont в конструкторе и DeleteObject в деструкторе, поэтому он очищает его когда он выходит за рамки.

Первый вопрос: разве я не закончу с АЛОТОМ классов, занимающихся этим? Тем более что у класса есть только конструктор и деструктор.

Второй вопрос: что если я вызываю класс CreateFont в WndProc, который постоянно выходит из области видимости. Так я должен делать все свои звонки на CreateFont или как LoadBitmap в WndMain? Я привык вызывать эти функции в WM_CREATE и очищать их в WM_DESTROY.

Ответы [ 4 ]

10 голосов
/ 26 сентября 2011

Вы можете избежать много скучной работы, используя шаблон, чтобы помочь вам. Например, если вы используете boost::shared_ptr, вы можете сделать:

#include <boost/shared_ptr.hpp>
#include <functional>

struct Font;

Font *createFont();
void deleteFont(Font*);

int main() {    
  boost::shared_ptr<Font> font(createFont(), std::ptr_fun(deleteFont));
}

Что избавляет вас от написания пользовательского класса для управления ресурсом. Если вам не доступны надстройки и TR1 или новее, все равно можно реализовать нечто подобное и универсальное, чтобы помочь вам.

boost::shared_ptr - это ссылка, подсчитанная правильно, поэтому, если вы хотите создать ее где-то и «продвинуть» ее, чтобы жить дольше, вы можете сделать это, скопировав ее куда-нибудь подольше, прежде чем она умрет.

4 голосов
/ 26 сентября 2011

Первый вопрос: разве я не закончу с АЛОТОМ классов, занимающихся этим?Тем более, что у класса есть только конструктор и деструктор.

Да, но есть несколько моментов, на которые следует обратить внимание:

  • это проблема?Классы будут небольшими, их будет легко читать и понимать,
  • многие из них можно будет использовать повторно (например, существует множество функций Win32, которые создают объекты HANDLE, и все онизакрыты таким же образом (с CloseHandle), так что вы можете использовать тот же класс для них.
  • вы можете использовать умный указатель или другую универсальную оболочку для заполнения большей части стандартного кода. Наиболее популярныйклассы интеллектуальных указателей позволяют указывать пользовательскую функцию удаления.

Второй вопрос: что если я вызываю класс CreateFont в WndProc, который постоянно выходит из области видимости.

Храните его в месте, где он не выйдет за рамки преждевременно. :) Здесь, интеллектуальные указатели могут быть полезны снова.Например, shared_ptr может использоваться, чтобы сохранить шрифт, пока на него указывает хотя бы один shared_ptr.Затем вы можете просто передать его из функции в какое-то обычное долгоживущее местоположение.

В противном случае, пока вы реализуете конструктор копирования и оператор присваивания (в C ++ 11 вы можете захотеть реализовать конструктор перемещения ивместо этого переместите назначение) для вашего класса RAII, его можно безопасно скопировать (или переместить) туда, куда вы хотите поместить его, даже если оно было создано в меньшей области действия.

1 голос
/ 26 сентября 2011

Первый вопрос: разве я не закончу с АЛОТОМ классов, занимающихся этим?Особенно потому, что у класса есть только конструктор и деконструктор

Если вам не нравится количество классов, которое вам нужно создать для каждого другого типа объекта, вы можете создать один класс RAII, которыйпринимает параметр HGDIOBJ в конструкторе и вызывает DeleteObject в деструкторе.Этот класс затем может быть использован для всех различных объектов GDI.Например:

class GDIObject
{
public:
    HGDIOBJ GdiObject;

    GDIObject( HGDIOBJ object )
        : GdiObject( object )
    {
    }

    ~GDIObject()
    {
        DeleteObject( GdiObject );
    }
}

...

GDIObject font( CreateFont( 48, 0, 0, 0, FW_DONTCARE, false, true, false, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Impact") ) );

Второй вопрос: что если я вызываю класс CreateFont в WndProc, который постоянно выходит из области видимости.Так я должен делать все свои вызовы CreateFont или как LoadBitmap в WndMain?Я привык вызывать эти функции в WM_CREATE и очищать их в WM_DESTROY.

Для элементов, которые должны оставаться в памяти дольше, чем область действия функции, вам придется поместить их вглобальный уровень.

0 голосов
/ 26 сентября 2011

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

В противном случае, да - у вас будет класс для любого ресурса, который требует явного освобождения - и хотя это трудоемко с точки зрения кода, это сэкономит вам массу времени на отладку вв долгосрочной перспективе (особенно в групповых проектах).Я бы все же сказал, что нужно использовать RAII, основываясь на ваших собственных чувствах к ситуации - это замечательная идея использовать его повсюду, но иногда при преобразовании старого кода может потребоваться огромный объем работы для исправления всех цепочек вызовов.использовать его.

Еще одна вещь - я не слишком знаком с логикой графического интерфейса, с которой вы работаете, поэтому я не буду специально ехать туда ... но вам придется разобраться, какВаши ресурсы должны быть скопированы и как долго они должны быть сохранены.Будут ли ваши контейнеры RAII подсчитывать ссылки или они будут иметь семантику значения (копирования)?Умные указатели подсчета ссылок, такие как shared_ptr, могут решить вашу проблему с воссозданием ресурсов, если вы можете передать ссылку на оригинал вокруг вашего кода.

...