티스토리 뷰

서론

 noexcept 를 이해하기 전에 C C++ 의 특징에 대해서 알고가는 것이 좋을것 같아 작성한다.

 C 는 하드웨어를 작성하기 위해 만들어진 언어이다. 그러다보니 프로그래머에게 많은 자유를 주어진다. 예를 들어 다른 언어와 다르게 메모리를 직접 관리할 수 있으며, 하드웨어 제어 또한 가능하다. 대신에 그로 인해 발생하는 댕글링 포인터와 같은 문제에 대해서는 책임지지 않는다. 이러한 특성이 C++ 에도 전달되어서인지 예외에 대한 책임은 온전히 프로그래머의 몫이다. 그로인한 특성으로 try catch 문이 문법으로 존재함에도 STL에서 try catch 문을 사용하지 않는다. 또한 예외에 대해 변경이 생긴다면 기존에 존재하던 프로그램에 문제를 일으킬 수 있다는 이유로 try catch 문과 같은 예외처리는 사용하지 않는다. 심지어 구글 코딩컨벤션을 살펴보면 try catch 문은 사용하지 않게 되어있다.. (실제로 안드로이드 프레임워크 코드를 살펴보면 try catch 문은 사용하지 않는다.) 

 시간이 계속 흐르면서 설계자들은 예외처리에 관해 한가지 의견을 갖고 있었다. 바로 예외가 방출하지 않는다는 조건만은 프로그래머에게 큰 도움이 된다는 것이다. 이것은 코드의 일관성 유지에도 도움을 주기 때문에 noexcept 라는 키워드가 탄생하게 되었다.

 throw()와 noecept

 noexcept 라는 키워드가 탄생하기 전에는 빈 throw 를 이용하여 예외가 없음을 나타내었다.

int f(int x) throw();   // C++98

int f(int x) noexcept;  // C++11

 위의 두 개의 함수는 같은 역할을 한다. 그러나 예외가 발생하게 되면 다른 결과를 나타낸다. C++98 에서는 예외 명세가 위반되며 호출스택이 풀리지만 C++11 에서는 풀릴 수도 있고 풀리지 않을수도 있다. noexcept 를 사용하면 컴파일러가 최적화를 시킬 가능성이 생기는 것이다.

이동생성자와 push_back

 기존의 vector push_back 함수는 doubling 을 할 때 복사 생성자를 호출하였다. C++11 에 오면서 이동 생성자를 호출하는 것이 더 좋은 성능을 나타내게 되었다. 여기에 문제가 있다. doubling 을 하던 도중 n 번째 객체를 이동(move)시키다가 에러가 발생했다고 하자. 먼저 이동이 완료된 객체들을 다시 복원해야하는데 이것이 불가능할 수도 있다. 그렇기 때문에 STL에서는 "가능하면 이동하되 필요하면 복사한다"는 전략을 사용한다. 이를 판단하는 기준이 바로 noexcept이다. 이동생성자에 noexcept 로 선언되어 있다면 이동생성자를 호출하고, 그렇지 않다면 복사생성자를 호출한다. 이는 swap 함수에서도 마찬가지이다. 

default로 noexcept가 선언되어 있는 함수

 noexcept 로 선언하는 것이 중요한 일부 함수들은 noexcept 를 사용하지 않아도 된다. 대표적으로 delete delete[] 는 예외를 방출하는것이 나쁜 코딩 스타일이다. 이에 따라 메모리 해제 함수와 모든 소멸자들은 암묵적으로 noexcept 이다. 명시적으로 noexcept(false) 로 선언되어 있는 멤버가 있다면 암묵적으로 noexcept 로 선언되지 않지만 그런 경우는 만나기 어려울 것이다. 

넓은 계약과 좁은 계약

 라이브러리 인터페이스 설계자 중에는 넓은 계약과 좁은 계약을 구분하는 사람이 있다. 넓은 계약을 가진 함수는 전제조건이 없는 함수를 말한다. 넓은 계약을 가진 함수는 프로그램의 상태와 무관하게 호출할 수 있으므로 noexcept 로 선언하기 더 쉽다. 이러한 특성 때문에 설계자들은 넓은 계약에서 noexcept 를 사용하는 경향이 있다.

주의사항

 noexcept 를 사용할 때는 항상 주의를 해야한다. 아래의 예시를 보자.

void setup();
void cleanup();

void doWork() noexcept
{
    setup();
    ...
    cleanup();
}

 noexcept 로 선언되어 있지 않은 setup cleanup 을 호출하는 doWork noexcept 로 되어 있다. setup cleanup 이 예외를 발생시킬 수 있는데 doWork noexcpet 인 것은 매우 모순되어 보인다. 하지만 컴파일러는 이를 경고해주지 않는다. 그 이유는 C 에서 옮겨온 라이브러리들의 경우 noexcept 로 선언되어 있지 않기 때문이다. 만약 실수로 noexcept 로 선언한다면 문제를 찾기 어려울 수 있으니 주의해야한다.

 

참고 서적

스콧 마이어스, Effective Modern C++
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함