Подтвердить что ты не робот

Дополнительные скобки скобки в коде С++

Иногда вы запускаете код с дополнительными скобками скобок, которые не имеют никакого отношения к области видимости, только для удобства чтения и предотвращения ошибок.

Например:

GetMutexLock( handle ) ; 
{
  // brace brackets "scope" the lock,
  // must close block / remember
  // to release the handle.
  // similar to C# lock construct
}
ReleaseMutexLock( handle ) ;

Другие места, которые я видел:

glBegin( GL_TRIANGLES ) ;
{
  glVertex3d( .. ) ;
  glVertex3d( .. ) ;
  glVertex3d( .. ) ;
} // must remember to glEnd!
glEnd() ; 

Это приводит к ошибке компилятора, если мьютекс не освобожден (при условии, что вы помните как вызов}, так и Release()).

  • Это плохая практика? Почему?
  • Если это не одно, может ли он изменить способ компиляции кода или сделать его медленнее?
4b9b3361

Ответ 1

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


Но в отношении ресурсов это плохая практика, потому что вы поставили себя в положение для утечки ресурса. Если что-либо в блоке бросает или возвращает, то вы мертвы.

Использовать управление ресурсами с привязкой к области (SBRM, также известное как RAII), которое ограничивает ресурс для области видимости с помощью деструктора:

class mutex_lock
{
public:
    mutex_lock(HANDLE pHandle) :
    mHandle(pHandle)
    {
        //acquire resource
        GetMutexLock(mHandle);
    }

    ~mutex_lock()
    {
        // release resource, bound to scope
        ReleaseMutexLock(mHandle);
    }

private:
    // resource
    HANDLE mHandle;

    // noncopyable
    mutex_lock(const mutex_lock&);
    mutex_lock& operator=(const mutex_lock&);
};

Итак, вы получаете:

{
  mutex_lock m(handle);
  // brace brackets "scope" the lock,
  // AUTOMATICALLY
}

У всех это будут ресурсы, чище и безопаснее. Если вы в состоянии сказать "Мне нужно освободить этот ресурс", вы сделали это неправильно; они должны обрабатываться автоматически.

Ответ 2

Брекеты влияют на область переменных. Насколько я знаю, это все, что они делают.

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

Часто это то, что вы хотите сделать. Например, ваш GetMutexLock и ReleaseMutexLock будут намного лучше кода на С++, написанных следующим образом:

struct MutexLocker {
  Handle handle;
  MutexLocker(handle) : handle(handle) { GetMutexLock(handle); }
  ~MutexLocker() { ReleaseMutexLock(handle); }    
};
...
{
  MutexLocker lock(handle);
  // brace brackets "scope" the lock,
  // must close block / remember
  // to release the handle.
  // similar to C# lock construct
}

Используя этот более стильный стиль С++, блокировка автоматически открывается в конце блока. Он будет выпущен при любых обстоятельствах, включая исключения, за исключением setjmp/longjmp или сбоя программы или прерывания.

Ответ 3

Это не плохая практика. Это не делает ничего медленнее; это всего лишь способ структурирования кода.

Получение компилятора для проверки ошибок и принудительного исполнения для вас всегда хорошо!

Ответ 4

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

Я не знаю, что вы подразумеваете под этим "это вводит ошибку компилятора, если мьютекс не освобожден". Это просто неправда. Такое использование { ... } не может и не будет приводить к ошибкам компилятора.

Является ли это хорошей практикой, это вопрос личных предпочтений. Все нормально. Кроме того, вы можете использовать комментарии и/или отступы для указания логической группировки операторов в коде без каких-либо дополнительных { ... }.

Существуют различные методы, основанные на определении области охвата, некоторые из которых были проиллюстрированы другими ответами здесь, но то, что вы имеете в своем OP, даже не отдаленно выглядит примерно так. Еще раз, то, что у вас есть в вашем OP (как показано), является исключительно привычкой форматирования исходного кода с избыточным { ... }, не влияющим на сгенерированный код.

Ответ 5

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

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

{
    mutex::scoped_lock lock(mutex);
    // brace brackets *really* scope the lock
}   // scoped_lock destructor releases the lock

{
    gl_group gl(GL_TRIANGLES); // calls glBegin()
    gl.Vertex3d( .. );
    gl.Vertex3d( .. );
    gl.Vertex3d( .. );
} // gl_group destructor calls glEnd()

Ответ 6

Все, что улучшает удобочитаемость IMHO, является хорошей практикой. Если добавление фигурных скобок помогает с удобочитаемостью, то идите!

Добавление дополнительных фигурных скобок не изменит способ компиляции кода. Это не приведет к замедлению работы программы.

Ответ 7

Это гораздо более полезно (IMHO) в С++ с деструкторами объектов; ваши примеры находятся на C.

Представьте, если вы создали класс MutexLock:

class MutexLock {
private:
    HANDLE handle;
public:
    MutexLock() : handle(0) {
        GetMutexLock(handle);
    }

    ~MutexLock() {
        ReleaseMutexLock(handle);
    }
}

Тогда вы можете обладать этой блокировкой только кодом, который ему нужен, предоставив новую область с фигурными скобками:

{
    MutexLock mtx;  // Allocated on the stack in this new scope

    // Use shared resource
}
// When this scope exits the destructor on mtx is called and the stack is popped

Ответ 8

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