[c++] C ++에서 불필요한 중괄호?

오늘 동료에 대한 코드 검토를 할 때 나는 독특한 것을 보았습니다. 그는 새 코드를 다음과 같이 중괄호로 묶었습니다.

Constructor::Constructor()
{
   existing code

   {
      New code: do some new fancy stuff here
   }

   existing code
}

이 결과는 무엇입니까? 이것을하는 이유는 무엇입니까? 이 습관은 어디에서 오는가?

편집하다:

아래의 입력 사항과 일부 질문에 따라 이미 답변을 표시했지만 질문에 일부를 추가해야한다고 생각합니다.

환경은 임베디드 장치입니다. C ++ 의류로 싸인 레거시 C 코드가 많이 있습니다. 많은 C 설정 C ++ 개발자가 있습니다.

이 코드 부분에는 중요한 섹션이 없습니다. 코드 의이 부분에서만 보았습니다. 주요 메모리 할당은 수행되지 않으며, 일부 플래그 만 설정되고, 약간의 비트가 발생합니다.

중괄호로 묶인 코드는 다음과 같습니다.

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
}

(코드를 신경 쓰지 말고 중괄호를 고수하십시오 …;)) 중괄호 뒤에 약간의 트위들 링, 상태 확인 및 기본 신호가 있습니다.

나는 그 남자와 이야기를 나누었고 그의 동기는 변수의 범위를 제한하고 충돌을 명명하며 실제로 얻을 수 없었던 다른 것들을 제한하는 것이 었습니다.

내 POV에서 이것은 다소 이상해 보이며 중괄호가 코드에 있어야한다고 생각하지 않습니다. 왜 중괄호로 코드를 묶을 수 있는지에 대한 모든 대답에서 좋은 예를 보았지만 대신 코드를 메소드로 분리해서는 안됩니까?



답변

새로운 (자동) 변수를보다 “깨끗하게”선언 할 수있는 새로운 범위를 제공하기 때문에 때때로 좋습니다.

여기서는 C++새로운 변수를 어디에서나 도입 할 수 있기 때문에 그렇게 중요하지는 않지만 습관은 CC99까지는 할 수 없었습니다. 🙂

C++소멸자가 있기 때문에 범위가 종료 될 때 리소스 (파일, 뮤텍스 등)를 자동으로 해제하는 것이 편리 할 수 ​​있습니다. 즉, 메서드를 시작할 때 잡은 것보다 짧은 시간 동안 일부 공유 리소스를 유지할 수 있습니다.


답변

한 가지 가능한 목적은 변수 범위제어하는 것입니다 . 또한 자동 저장 기능이있는 변수는 범위를 벗어나면 소멸되므로 소멸자가 다른 방법보다 먼저 호출 될 수 있습니다.


답변

추가 괄호는 괄호 안에 선언 된 변수의 범위를 정의하는 데 사용됩니다. 변수가 범위를 벗어날 때 소멸자가 호출되도록 수행됩니다. 소멸자에서 다른 사람이 그것을 얻을 수 있도록 뮤텍스 (또는 다른 리소스)를 해제 할 수 있습니다.

내 프로덕션 코드에서 다음과 같이 작성했습니다.

void f()
{
   //some code - MULTIPLE threads can execute this code at the same time

   {
       scoped_lock lock(mutex); //critical section starts here

       //critical section code
       //EXACTLY ONE thread can execute this code at a time

   } //mutex is automatically released here

  //other code  - MULTIPLE threads can execute this code at the same time
}

보시다시피, 이런 식 scoped_lock 으로 함수에서 사용할 수 있으며 동시에 추가 괄호를 사용하여 범위를 정의 할 수 있습니다. 이렇게하면 추가 괄호 외부의 코드를 여러 스레드에서 동시에 실행할 수 있지만 괄호 내부의 코드는 한 번정확히 하나의 스레드 로 실행됩니다 .


답변

다른 사람들이 지적했듯이 새로운 블록은 새로운 범위를 도입하여 주변 코드의 네임 스페이스를 폐기하지 않고 필요 이상으로 리소스를 사용하지 않는 자체 변수로 코드를 작성할 수 있습니다.

그러나 이렇게하는 또 다른 좋은 이유가 있습니다.

특정 (하위) 목적을 달성하는 코드 블록을 분리하는 것입니다. 하나의 문장이 내가 원하는 계산 효과를 얻는 것은 드 rare니다. 보통 몇 개가 걸립니다. 주석으로 블록에 배치하면 독자에게 (나중에 나 자신에게) 말할 수 있습니다.

  • 이 덩어리는 일관된 개념적 목적을 가지고 있습니다.
  • 필요한 모든 코드는 다음과 같습니다.
  • 그리고 청크에 대한 의견이 있습니다.

예 :

{  // update the moving average
   i= (i+1) mod ARRAYSIZE;
   sum = sum - A[i];
   A[i] = new_value;
   sum = sum + new_value;
   average = sum / ARRAYSIZE ;
}

모든 것을 수행하는 함수를 작성해야한다고 주장 할 수 있습니다. 한 번만 수행하면 함수를 작성하면 구문과 매개 변수가 추가됩니다. 작은 점이 보인다. 이것을 매개 변수가없는 익명 함수로 생각하십시오.

운이 좋으면 편집기에 블록을 숨길 수있는 접기 / 펴기 기능이 있습니다.

나는 항상 이것을한다. 검사해야 할 코드의 경계를 아는 것이 큰 즐거움이며, 해당 청크가 내가 원하는 것이 아니라면 어떤 행도 볼 필요가 없다는 것을 아는 것이 좋습니다.


답변

새로운 중괄호 블록 안에 선언 된 모든 변수의 수명이이 블록으로 제한되기 때문일 수 있습니다. 마음에 드는 또 다른 이유는 자주 사용하는 편집기에서 코드 접기를 사용할 수 있기 때문입니다.


답변

이것은 if( 없이while ) (또는 등) 블록 과 동일 합니다. 즉, 제어 구조를 도입하지 않고 범위를 소개합니다. if

이 “명시 적 범위 지정”은 일반적으로 다음과 같은 경우에 유용합니다.

  1. 이름 충돌을 피하기 위해.
  2. 범위를 정하십시오 using.
  3. 소멸자가 호출되는시기를 제어합니다.

예 1 :

{
    auto my_variable = ... ;
    // ...
}

// ...

{
    auto my_variable = ... ;
    // ...
}

경우 my_variable특히 좋은 될 일이 이름을 서로 분리에 사용되는 두 가지 변수에 대해 다음 명시 적 범위 지정은 그냥 이름 충돌을 피하기 위해 새 이름을 발명 피할 수 있습니다.

또한 my_variable실수로 의도 한 범위 를 벗어나는 것을 피할 수 있습니다 .

예 2 :

namespace N1 { class A { }; }
namespace N2 { class A { }; }

void foo() {

    {
        using namespace N1;
        A a; // N1::A.
        // ...
    }

    {
        using namespace N2;
        A a; // N2::A.
        // ...
    }

}

이것이 유용한 실제 상황은 드물고 리팩토링을 위해 코드가 익었 음을 나타낼 수 있지만, 실제로 필요한 메커니즘이 있습니다.

예 3 :

{
    MyRaiiClass guard1 = ...;

    // ...

    {
        MyRaiiClass guard2 = ...;
        // ...
    } // ~MyRaiiClass for guard2 called.

    // ...

} // ~MyRaiiClass for guard1 called.

자원을 확보해야 할 필요성이 자연스럽게 기능 또는 제어 구조의 경계에 “떨어지지”않는 경우 RAII 에 중요 할 수 있습니다 .


답변

이것은 다중 스레드 프로그래밍에서 중요 섹션과 함께 범위 잠금을 사용할 때 실제로 유용합니다. 중괄호 (일반적으로 첫 번째 명령)로 초기화 된 범위 잠금은 블록 끝에서 범위를 벗어나므로 다른 스레드를 다시 실행할 수 있습니다.