Понимание значения слова и понятия - RAII (Приобретением ресурса является Инициализация),

Вы можете использовать ПЕРЕКЛЮЧАТЕЛЬ или несколько ИИФ для группы категорий, чтобы сгруппировать данные в диаграмме.

Для групповых выражений вам понадобится что-то вроде

=SWTICH(Fields!Number.Value < 2500, "< 2,500", 
    Fields!Number.Value >= 2500 AND Fields!Number.Value <= 4999, "2500 - 4999",
    Fields!Number.Value >= 5000 AND Fields!Number.Value <= 7499, "5000 - 7499", 
    Fields!Number.Value >= 7500 AND Fields!Number.Value <= 9999, "7500 - 9999",
    Fields!Number.Value >= 10000, "10000+")

Или вы можете использовать вложенные ИИФ:

=IIF(Fields!Number.Value < 2500, "< 2,500", 
 IIF(Fields!Number.Value >= 2500 AND Fields!Number.Value <= 4999, "2500 - 4999",
 IIF(Fields!Number.Value >= 5000 AND Fields!Number.Value <= 7499, "5000 - 7499",
 IIF(Fields!Number.Value >= 7500 AND Fields!Number.Value <= 9999, "7500 - 9999",
 IIF(Fields!Number.Value >= 10000, "10000+", "Unknown")))))
108
задан Aquarius_Girl 22 April 2014 в 09:13
поделиться

10 ответов

Итак, почему не то, который назвал "использование стека для инициирования очистки" (UTSTTC:)?

RAII говорит Вам, что сделать: Получите свой ресурс в конструкторе! Я добавил бы: один ресурс, один конструктор. UTSTTC является всего одним приложением, которого, RAII намного больше.

Управление ресурсами сосет. Здесь, ресурс - что-либо, чему нужна очистка после использования. Исследования проектов через многие платформы показывают, что большинство ошибок связано с управлением ресурсами - и это особенно плохо в Windows (из-за многих типов объектов и средств выделения).

В C++ управление ресурсами является особенно сложным из-за комбинации исключений и (стиль C++) шаблоны. Для быстрого взгляда под капотом см. GOTW8).


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

Давайте запустимся с чрезмерно упрощенного FileHandle класс, использующий RAII:

class FileHandle
{
    FILE* file;

public:

    explicit FileHandle(const char* name)
    {
        file = fopen(name);
        if (!file)
        {
            throw "MAYDAY! MAYDAY";
        }
    }

    ~FileHandle()
    {
        // The only reason we are checking the file pointer for validity
        // is because it might have been moved (see below).
        // It is NOT needed to check against a failed constructor,
        // because the destructor is NEVER executed when the constructor fails!
        if (file)
        {
            fclose(file);
        }
    }

    // The following technicalities can be skipped on the first read.
    // They are not crucial to understanding the basic idea of RAII.
    // However, if you plan to implement your own RAII classes,
    // it is absolutely essential that you read on :)



    // It does not make sense to copy a file handle,
    // hence we disallow the otherwise implicitly generated copy operations.

    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;



    // The following operations enable transfer of ownership
    // and require compiler support for rvalue references, a C++0x feature.
    // Essentially, a resource is "moved" from one object to another.

    FileHandle(FileHandle&& that)
    {
        file = that.file;
        that.file = 0;
    }

    FileHandle& operator=(FileHandle&& that)
    {
        file = that.file;
        that.file = 0;
        return *this;
    }
}

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

RAII избегает использования объектов в недопустимом состоянии. это уже делает жизнь легче, прежде чем мы даже будем использовать объект.

Теперь, давайте взглянем на временные объекты:

void CopyFileData(FileHandle source, FileHandle dest);

void Foo()
{
    CopyFileData(FileHandle("C:\\source"), FileHandle("C:\\dest"));
}

Существует три ошибочных случая к обработанному: никакой файл не может быть открыт, только один файл может быть открыт, оба файла могут быть открыты, но копирование файлов отказавшее. В non-RAII реализации, Foo должен был бы обработать все три случая явно.

RAII высвобождает средства, которые были получены, даже когда несколько ресурсов получены в одном операторе.

Теперь, позвольте нам совокупный некоторые объекты:

class Logger
{
    FileHandle original, duplex;   // this logger can write to two files at once!

public:

    Logger(const char* filename1, const char* filename2)
    : original(filename1), duplex(filename2)
    {
        if (!filewrite_duplex(original, duplex, "New Session"))
            throw "Ugh damn!";
    }
}

Конструктор Logger перестанет работать если originalконструктор перестал работать (потому что filename1 не мог быть открыт), duplexконструктор перестал работать (потому что filename2 не мог быть открыт), или пишущий в файлы внутри Loggerсбои тела конструктора. В любом из этих случаев, Loggerдеструктор не назовут - таким образом, мы не сможем полагаться Loggerдеструктор для выпуска файлов. Но если original был создан, его деструктор назовут во время очистки Logger конструктор.

RAII упрощает очистку после частичной конструкции.


Отрицательные моменты:

Отрицательные моменты? Все проблемы могут быть решены с RAII и интеллектуальными указателями ;-)

RAII является иногда громоздким при необходимости в задержанном приобретении, продвигая агрегированные объекты на "кучу".
Предположите, что Регистратору нужен a SetTargetFile(const char* target). В этом случае, дескриптор, который все еще должен быть членом Logger, потребности находиться на "куче" (например, в интеллектуальном указателе, инициировать разрушение дескриптора соответственно.)

Я никогда не желал сборки "мусора" действительно. Когда я делаю C#, я иногда чувствую момент счастья, о котором я просто не должен заботиться, но намного больше я пропускаю все прохладные игрушки, которые могут быть созданы посредством детерминированного разрушения. (использование IDisposable просто не сокращает его.)

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


Примечание по образцу FileHandle: Это не было предназначено, чтобы быть завершенным, просто образец - но оказалось неправильным. Благодарен за то, что Johannes Schaub указывает и FredOverflow для того, чтобы превратить его в корректный C++ 0x решение. Со временем я обосновался с подходом, зарегистрированным здесь.

130
ответ дан peterchen 24 November 2019 в 03:30
поделиться

RAII использует семантику деструкторов C++ для управления ресурсами. Например, рассмотрите интеллектуальный указатель. У Вас есть параметризованный конструктор указателя, который инициализирует этот указатель с адресом объекта. Вы выделяете указатель на стеке:

SmartPointer pointer( new ObjectClass() );

Когда интеллектуальный указатель выходит из объема, деструктор класса указателя удаляет подключенный объект. Указатель выделяется стеку и объект - выделенный "куче".

Существуют определенные случаи, когда RAII не помогает. Например, если Вы используете интеллектуальные указатели подсчета ссылок (как повышение:: shared_ptr), и создают подобную графику структуру с циклом, Вы рискуете сталкиваться с утечкой памяти, потому что объекты в цикле будут препятствовать друг другу быть выпущенными. Сборка "мусора" помогла бы против этого.

10
ответ дан sharptooth 24 November 2019 в 03:30
поделиться

Я соглашаюсь с cpitis. Но хотел бы добавить, что ресурсы могут быть чем-либо не просто память. Ресурс мог быть файлом, критическим разделом, потоком или соединением с базой данных.

Это называют, Приобретение Ресурса Является Инициализацией, потому что ресурс получен, когда объект, управляющий ресурсом, создается, Если конструктор перестал работать (т.е. из-за исключения), ресурс не получен. Затем, после того как объект выходит из объема, ресурс выпущен. C++ гарантирует, что все объекты на стеке, которые были успешно созданы, будут разрушены (это включает конструкторов базовых классов и участников, даже если конструктор суперкласса перестал работать).

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

8
ответ дан iain 24 November 2019 в 03:30
поделиться

Я хотел бы поместить его немного более сильно затем предыдущие ответы.

RAII, Приобретение Ресурса Является средствами Инициализации, что все полученные ресурсы должны быть получены в контексте инициализации объекта. Это запрещает "явное" приобретение ресурса. Объяснение - то, что очистка в C++ работает на объектной основе, не основании вызова функции. Следовательно, вся очистка должна быть сделана объектами, не вызовами функции. В этом смысле C++ более - объектно-ориентированный затем, например, Java. Очистка Java основана на вызовах функции в finally пункты.

8
ответ дан MSalters 24 November 2019 в 03:30
поделиться

Проблема со сборкой "мусора" состоит в том, что Вы теряете детерминированное разрушение, это крайне важно для RAII. После того как переменная выходит из объема, это до сборщика "мусора", когда объект будет исправлен. Ресурс, которым это сохранено объектом, продолжит быть сохраненным, пока деструктор не называют.

7
ответ дан Mark Ransom 24 November 2019 в 03:30
поделиться

И как можно сделать что-то на стеке, который вызовет очистку чего-то, что живет на "куче"?

class int_buffer
{
   size_t m_size;
   int *  m_buf;

   public:
   int_buffer( size_t size )
     : m_size( size ), m_buf( 0 )
   {
       if( m_size > 0 )
           m_buf = new int[m_size]; // will throw on failure by default
   }
   ~int_buffer()
   {
       delete[] m_buf;
   }
   /* ...rest of class implementation...*/

};


void foo() 
{
    int_buffer ib(20); // creates a buffer of 20 bytes
    std::cout << ib.size() << std::endl;
} // here the destructor is called automatically even if an exception is thrown and the memory ib held is freed.

Когда экземпляр int_buffer появляется, он должен иметь размер, и он выделит необходимую память. То, когда это выходит из объема, это - деструктор, называют. Это очень полезно для вещей как объекты синхронизации. Рассмотреть

class mutex
{
   // ...
   take();
   release();

   class mutex::sentry
   {
      mutex & mm;
      public:
      sentry( mutex & m ) : mm(m) 
      {
          mm.take();
      }
      ~sentry()
      {
          mm.release();
      }
   }; // mutex::sentry;
};
mutex m;

int getSomeValue()
{
    mutex::sentry ms( m ); // blocks here until the mutex is taken
    return 0;  
} // the mutex is released in the destructor call here.

Кроме того, есть ли случаи, где Вы не можете использовать RAII?

Нет, не действительно.

Вы когда-либо желаете сборки "мусора"? По крайней мере, сборщик "мусора" Вы могли использовать для некоторых объектов, позволяя другим управляться?

Никогда. Сборка "мусора" только решает очень небольшое подмножество динамического управления ресурсами.

3
ответ дан Jeremiah Willcock 24 November 2019 в 03:30
поделиться

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

По сравнению с собравшими "мусор" языками/технологиями (например, Java.NET), C++ позволяет полный контроль над жизнью объекта. Для стека выделенный объект Вы будете знать, когда деструктор объекта назовут (когда выполнение выйдет из объема), вещь, которой действительно не управляют в случае сборки "мусора". Даже с помощью интеллектуальных указателей в C++ (например, повышение:: shared_ptr), Вы будете знать, что, когда нет никакой ссылки на резкий объект, деструктор того объекта назовут.

4
ответ дан Cătălin Pitiș 24 November 2019 в 03:30
поделиться

Уже существует много хороших ответов здесь, но я был бы точно так же, как для добавления:
Простое объяснение RAII состоит в том, что в C++ объект, выделенный на стеке, уничтожается каждый раз, когда он выходит из объема. Это означает, деструктор объектов назовут и может сделать всю необходимую очистку.
Это означает, если объект создается без "нового", нет "удалите", требуется. И это - также идея позади "интеллектуальных указателей" - они находятся на стеке, и по существу переносит основанный на "куче" объект.

2
ответ дан E Dominique 24 November 2019 в 03:30
поделиться

RAII является акронимом для Приобретения Ресурса, Инициализация.

Эта техника очень уникальна для C++ из-за их поддержки обоих Конструкторов и Деструкторов и почти автоматически конструкторов, которые соответствуют этому аргументы, передаваемые в или худший случай, которым конструктора по умолчанию называют и деструкторы, если обеспеченный explicity называют иначе по умолчанию, который добавляется компилятором C++, назван, если Вы не записали деструктор явно для класса C++. Это происходит только для объектов C++, которыми автоуправляют - значение, которые не используют свободное хранилище (память выделила/освободила использование, новое, новое [] / удаляют, удаляют [] операторы C++).

Метод RAII использует эту функцию автоуправляемого объекта для обработки объектов, которые создаются на heap/free-store просьбой explcitly о большей памяти, использующей новый/новый [], который должен быть явно уничтожен вызовом, удаляют/удаляют []. Класс автоуправляемого объекта перенесет этот другой объект, который создается на heap/free-store памяти. Следовательно, когда конструктор автоуправляемого объекта выполняется, перенесенный объект создается на heap/free-store памяти и когда дескриптор автоуправляемого объекта выходит из объема, деструктор того автоуправляемого объекта называют автоматически, в котором перенесенный объект уничтожается с помощью, удаляют. С понятиями ООП при обертывании таких объектов в другом классе в частном объеме у Вас не было бы доступа к перенесенным участникам классов и методам, и это - причина, почему интеллектуальные указатели (иначе классы дескриптора) разработаны для. Эти интеллектуальные указатели выставляют перенесенный объект как типизированный объект к внешнему миру и там позволяя вызывать любых участников/методы, из которых составлен выставленный объект памяти. Обратите внимание, что интеллектуальные указатели имеют различные разновидности на основе различных потребностей. Необходимо обратиться к современному программированию на C++ Andrei Alexandrescu или стимулировать библиотеку (www.boostorg) shared_ptr.hpp реализация/документация для получения дополнительной информации о нем. Надежда это помогает Вам понять RAII.

1
ответ дан techcraver 24 November 2019 в 03:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: