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

问题描述 投票:13回答:8

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

例如:

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. 如果它不是一个,它可以改变代码编译的方式或使其变慢吗?
c++ curly-braces
8个回答
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
}

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


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或程序崩溃或中止除外。


3
投票

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

让编译器为您执行错误检查和执行总是一件好事!


3
投票

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

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

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

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


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
投票

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

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


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

1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.