2010-08-25 6 views
12

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

Например:

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. Если это не так, не может ли он изменить способ компиляции кода или сделать его медленнее?
+2

В OpenGL эта практика предназначена для повышения удобочитаемости кода. Скобки на вызовах glBegin() действуют как визуальный разделитель группы вершин, который должен быть нарисован. – karlphillip

+0

Это ужасная практика! Почему кто-то будет использовать разделители блоков, чтобы выделить блок кода вне меня. Я могу представить себе все микро-микро-оптимизации, которые им не хватает ...все приносили в жертву за что-то вроде как читабельность. Какой мир подходит к ???? –

+1

@Noah, я переименовал вас в Sarcastic Cat. – bobobobo

ответ

30

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


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

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

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

+7

+1 для правильности ... и это новое сокращение SBRM, о котором я не знал! Гораздо лучше, чем RAII, если выразить намерение. И даже не кажется, что это страница с википедией! –

3

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

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

+0

+1 для получения компилятора для выполнения вашей работы ... –

+2

, к сожалению, освобождение ресурса самостоятельно подвержено ошибкам ... –

1

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

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

+0

{I {think {{{{{{{}} {} {} {{{{}}}}}} , Серьезно, скобки говорят мне: «здесь есть контрольная структура». Когда его нет, я все равно ищу его. Причинение мне потратить познание и долю секунды искать что-то, чего нет, нет читаемости. –

+0

@David - Я не думаю, что OP думал о добавлении произвольного количества фигурных скобок к коду, как в вашем примере. Я имел в виду, как OP использовал брекеты. Очевидно, что добавление фигурных скобок, как в вашем примере, не помогает с удобочитаемостью. – Starkey

+0

Использование фигурных скобок для любых целей, отличных от указания структуры управления, не помогает с удобочитаемостью, насколько я могу судить. Это не считается структурой управления. Использование их для ограничения объема ресурса, выделенного RAII. –

17

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

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

Часто это то, что вы хотите сделать. Например, ваш 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 или сбоя программы или прерывания.

+0

Это правильный путь. – Puppy

+12

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

+0

Правильный синтаксис - это дескриптор MutexLocker; ', а не' MutexLocker (handle); '. – kennytm

2

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

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

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

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

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

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

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

1

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

3

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

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

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

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

+0

Кажется, вы единственный, кто прокомментировал ошибку «ошибка компилятора» - хорошо видно. У меня сложилось впечатление, что плакат видел макросы, используемые как это: begin_x // делать вещи END_X где begin_x и END_X замены включают свои собственные {и}, что недостающий END_X действительно производит ошибку компилятора. Уродливые вещи. –

+0

@Tony: У Boost есть несколько из них. Я когда-то ошибся на сто страниц, потому что забыл. «Уродливые вещи» не начинают описывать это :) –

 Смежные вопросы

  • Нет связанных вопросов^_^