Дополнительные скобки в коде C ++ - PullRequest
13 голосов
/ 25 августа 2010

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

Например:

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

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

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

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

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

Ответы [ 8 ]

32 голосов
/ 25 августа 2010

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


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

Используйте управление ресурсами на уровне области (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
}

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

17 голосов
/ 25 августа 2010

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

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

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

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#'s lock construct
}

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

3 голосов
/ 25 августа 2010

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

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

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

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

3 голосов
/ 25 августа 2010

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

Заставить компилятор проверять и применять ошибки всегда полезно -

2 голосов
/ 25 августа 2010

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

2 голосов
/ 25 августа 2010

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

Лично я бы назвал это плохой практикой; способ избежать ошибок, которые вы можете здесь совершить, - это использовать управление ресурсами с областью действия (иногда называемое 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()
1 голос
/ 25 августа 2010

Это гораздо полезнее (IMHO) в C ++ с деструкторами объектов; ваши примеры в 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
1 голос
/ 25 августа 2010

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

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

...