C ++代码中的额外括号括号

时间:2010-08-25 17:12:29

标签: c++ curly-braces

有时你遇到的代码有额外的括号括号,与范围无关,只是为了便于阅读和避免错误。

例如:

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 个答案:

答案 0 :(得分:31)

支撑本身很好,他们所做的就是限制范围,你不会放慢任何速度。它可以被视为更清洁。 (总是比快速代码更喜欢干净的代码,如果它更干净,在你描述之前不要担心速度。)


但是就资源而言,这是不好的做法,因为你已经让自己处于泄漏资源的位置。如果块中的任何东西抛出或返回,那么你已经死了。

使用范围绑定资源管理(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
}

这会所有资源,它更干净,更安全。如果你能够说“我需要释放这个资源”,你就做错了;它们应该自动处理。

答案 1 :(得分: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或程序崩溃或中止除外。

答案 2 :(得分:3)

这不是一种糟糕的做法。它不会使任何东西变慢;它只是构建代码的一种方式。

让编译器进行错误检查&为你执行总是一件好事!

答案 3 :(得分:3)

{ ... }在原始示例中的具体位置纯粹是通过使一组逻辑相关的语句开始和结束的位置更加明显的格式化糖。如示例所示,它对编译的代码没有影响。

我不知道你的意思是“如果未释放互斥锁,则会引入编译器错误”。这根本不是真的。 { ... }的这种使用不会也不会引入任何编译器错误。

这是一个好的做法是个人偏好的问题。看起来不错。或者,您可以使用注释和/或缩进来指示代码中语句的逻辑分组,而无需任何额外的{ ... }

有各种基于范围的技术,其中一些已经通过其他答案进行了说明,但是您在OP中所拥有的技术甚至看起来都不是那样的。再一次,你在OP中拥有的东西(如图所示)纯粹是一种源代码格式化习惯,多余的{ ... }对生成的代码没有任何影响。

答案 4 :(得分: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()

答案 5 :(得分:2)

如果您将代码放入大括号中,您应该将其分解为自己的方法。如果它是一个单独的单元,为什么不标记它并在功能上将其分解?这将使它明确阻止块的作用,后来读取代码的人将不必弄明白。

答案 6 :(得分:1)

任何提高可读性的东西恕我直言都是好习惯。如果添加大括号有助于提高可读性,那就去吧!

添加额外的大括号不会改变代码的编译方式。它不会使程序的运行速度变慢。

答案 7 :(得分:1)

这在使用对象析构函数的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