C++ поддерживает 'наконец' блоки? (И каков этот 'RAII', о котором я продолжаю слышать?)

Я хотел бы указать, что нет такой вещи, как инициализация двойной скобки. Существует только обычный традиционный блок инициализации брекетов. Второй блок фигурных скобок не имеет ничего общего с инициализацией. Ответы говорят, что эти две фигурные скобки инициализируют что-то, но это не так.

Во-вторых, почти все ответы говорят о том, что это используется при создании анонимных внутренних классов. Я думаю, что люди, читающие эти ответы, получат впечатление, что это используется только при создании анонимных внутренних классов. Но он используется во всех классах. Чтение этих ответов - это какое-то новое особое будущее, посвященное анонимным классам, и я думаю, что это вводит в заблуждение.

. Идем дальше, этот вопрос говорит о ситуации, когда вторая открывающая скобка находится сразу после первого открытия скобки. Обычно в обычном классе есть некоторый код между двумя фигурными скобками, но это абсолютно одно и то же. Так что это вопрос размещения скобок. Поэтому я думаю, что мы не должны говорить, что это какая-то новая захватывающая вещь, потому что это то, что мы все знаем, но просто написано с некоторым кодом между скобками. Мы не должны создавать новую концепцию, называемую «инициализация двойной скобки».

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

Кроме того, мы не должны говорить о проблеме, созданной используя эту несуществующую вещь «инициализацию двойной скобки» или даже обычную инициализацию одной скобки, поскольку описанные проблемы существуют только из-за создания анонимного класса, поэтому он не имеет ничего общего с исходным вопросом. Но все ответы дают читателям впечатление, что это не вина в создании анонимных классов, а эта злая (несуществующая) вещь, называемая «инициализация двойной скобки».

260
задан Motti 14 September 2011 в 02:33
поделиться

6 ответов

Нет, C++ не поддерживает 'наконец' блоки. Причина состоит в том, что C++ вместо этого поддерживает RAII: "Приобретение ресурса Является Инициализацией" - плохое имя <глоток> †для действительно полезного понятия.

идея состоит в том, что деструктор объекта ответственен за освобождение ресурсов. Когда объект будет иметь продолжительность автоматического хранения, деструктор объекта назовут, когда блок, в котором это было создано выходы - даже когда из того блока выходят в присутствии исключения. Вот объяснение Bjarne Stroustrup из темы.

общее использование А для RAII блокирует взаимное исключение:

// A class with implements RAII
class lock
{
    mutex &m_;

public:
    lock(mutex &m)
      : m_(m)
    {
        m.acquire();
    }
    ~lock()
    {
        m_.release();
    }
};

// A class which uses 'mutex' and 'lock' objects
class foo
{
    mutex mutex_; // mutex for locking 'foo' object
public:
    void bar()
    {
        lock scopeLock(mutex_); // lock object.

        foobar(); // an operation which may throw an exception

        // scopeLock will be destructed even if an exception
        // occurs, which will release the mutex and allow
        // other functions to lock the object and run.
    }
};

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

Для знакомых с C# или VB.NET, можно распознать, что RAII подобен .NET детерминированное разрушение с помощью IDisposable и с помощью операторов . Действительно, эти два метода очень похожи. Основное различие - то, что RAII детерминировано выпустит любой тип ресурса - включая память. При реализации IDisposable в.NET (даже C++ языка.NET / CLI), средства будут детерминировано высвобождены за исключением памяти. В.NET детерминировано не освобождена память; память только освобождена во время циклов сборки "мусора".

 

†Некоторые люди полагают, что "Разрушение является Отказом Ресурса", более точное название идиомы RAII.

262
ответ дан alwaysmpe 23 November 2019 в 02:37
поделиться

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

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

30
ответ дан Michael Burr 23 November 2019 в 02:37
поделиться

В C++ наконец НЕ требуются из-за RAII.

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

Также IMO код выглядит более опрятным (см. ниже).

Пример:

объект базы данных А. Для проверки соединение с БД используется, оно должно быть открыто и закрыто. При помощи RAII это может быть сделано в конструкторе/деструкторе.

C++ Как RAII

void someFunc()
{
    DB    db("DBDesciptionString");
    // Use the db object.

} // db goes out of scope and destructor closes the connection.
  // This happens even in the presence of exceptions.

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

Java Как Наконец

void someFunc()
{
    DB      db = new DB("DBDesciptionString");
    try
    {
        // Use the db object.
    }
    finally
    {
        // Can not rely on finaliser.
        // So we must explicitly close the connection.
        try
        {
            db.close();
        }
        catch(Throwable e)
        {
           /* Ignore */
           // Make sure not to throw exception if one is already propagating.
        }
    }
}

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

Также это - простой пример.
, Когда у Вас есть несколько средств, которые должны быть высвобождены, код может быть сложным.

А более подробный анализ может быть найден здесь: http://accu.org/index.php/journals/236

76
ответ дан johnchen902 23 November 2019 в 02:37
поделиться

FWIW, Microsoft Visual C++ действительно поддерживает попытку, наконец и это исторически использовалось в приложениях MFC в качестве метода ловли серьезных исключений, которые иначе приведут к катастрофическому отказу. Например;

int CMyApp::Run() 
{
    __try
    {
        int i = CWinApp::Run();
        m_Exitok = MAGIC_EXIT_NO;
        return i;
    }
    __finally
    {
        if (m_Exitok != MAGIC_EXIT_NO)
            FaultHandler();
    }
}

я использовал это в прошлом, чтобы сделать, вещам нравится, сохраняют резервные копии открытых файлов до выхода. Определенные настройки отладки JIT повредят этот механизм все же.

6
ответ дан SmacL 23 November 2019 в 02:37
поделиться
try
{
  ...
  goto finally;
}
catch(...)
{
  ...
  goto finally;
}
finally:
{
  ...
}
-2
ответ дан 23 November 2019 в 02:37
поделиться

Извините за обнаружение такого старого потока, но есть серьезная ошибка в следующих рассуждениях:

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

Чаще всего приходится иметь дело с динамически выделяемыми объектами, динамическим числом объектов и т. Д. В блоке try некоторый код может создавать много объектов (сколько определяется во время выполнения) и сохранять указатели на них в список. Это не экзотический сценарий, а очень распространенный. В этом случае вы захотите написать что-то вроде

void DoStuff(vector<string> input)
{
  list<Foo*> myList;

  try
  {    
    for (int i = 0; i < input.size(); ++i)
    {
      Foo* tmp = new Foo(input[i]);
      if (!tmp)
        throw;

      myList.push_back(tmp);
    }

    DoSomeStuff(myList);
  }
  finally
  {
    while (!myList.empty())
    {
      delete myList.back();
      myList.pop_back();
    }
  }
}

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

Вместо этого вы должны пойти по уродливому пути:

void DoStuff(vector<string> input)
{
  list<Foo*> myList;

  try
  {    
    for (int i = 0; i < input.size(); ++i)
    {
      Foo* tmp = new Foo(input[i]);
      if (!tmp)
        throw;

      myList.push_back(tmp);
    }

    DoSomeStuff(myList);
  }
  catch(...)
  {
  }

  while (!myList.empty())
  {
    delete myList.back();
    myList.pop_back();
  }
}

Также: почему даже управляемые языки предоставляют finally-блок, несмотря на то, что ресурсы в любом случае автоматически освобождаются сборщиком мусора?

Подсказка: вы можете еще больше делать с "наконец", чем просто освобождение памяти.

7
ответ дан 23 November 2019 в 02:37
поделиться
Другие вопросы по тегам:

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