거기에 훌륭한 답변이 있으므로 잊혀진 것들을 추가합니다.
0. RAII는 범위에 관한 것입니다.
RAII는 다음 두 가지에 관한 것입니다.
- 생성자에서 리소스 (어느 리소스에 관계없이)를 획득하고 소멸자에서 획득을 해제합니다.
- 변수가 선언되면 생성자가 실행되고 변수가 범위를 벗어나면 소멸자가 자동으로 실행됩니다.
다른 사람들은 이미 그것에 대해 대답 했으므로 자세히 설명하지 않겠습니다.
1. Java 또는 C #으로 코딩 할 때 이미 RAII를 사용하고 있습니다.
MONSIEUR JOURDAIN : 뭐! 내가 "니콜, 내 슬리퍼 가져와 내 나이트캡 줘"라고 말하면 그게 산문이야?
철학 석사 : 네, 선생님.
MONSIEUR JOURDAIN : 40 년이 넘도록 나는 그것에 대해 아무것도 알지 못한 채 산문을 말하고 있으며, 그것을 가르쳐 준 것에 대해 당신에게 많은 의무가 있습니다.
— 몰리에르 : 중산층 신사, 2 막, 4 장
Monsieur Jourdain이 산문에서했던 것처럼 C #과 심지어 Java 사람들은 이미 RAII를 사용하지만 숨겨진 방식으로 사용합니다. 예를 들어 다음 Java 코드 (를로 대체 synchronized
하여 C #에서 동일한 방식으로 작성 됨 lock
) :
void foo()
{
// etc.
synchronized(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
... 이미 RAII를 사용하고 있습니다 : 뮤텍스 획득은 키워드 ( synchronized
또는lock
)에서 수행되며 스코프를 종료 할 때 획득 해제가 수행됩니다.
표기법이 너무 자연 스럽기 때문에 RAII에 대해 들어 본 적이없는 사람들에게도 설명이 거의 필요하지 않습니다.
여기서 C ++가 Java 및 C #에 비해 갖는 장점은 RAII를 사용하여 무엇이든 만들 수 있다는 것입니다. 예를 들어, synchronized
또는lock
++ C에서, 그러나 우리는 여전히있을 수 있습니다.
C ++에서는 다음과 같이 작성됩니다.
void foo()
{
// etc.
{
Lock lock(someObject) ; // lock is an object of type Lock whose
// constructor acquires a mutex on
// someObject and whose destructor will
// un-acquire it
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
Java / C # 방식으로 쉽게 작성할 수 있습니다 (C ++ 매크로 사용).
void foo()
{
// etc.
LOCK(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
2. RAII는 다른 용도로 사용됩니다.
WHITE RABBIT : [노래] 늦었 어 / 늦었 어 / 아주 중요한 데이트를 위해. / "안녕하세요"라고 말할 시간이 없습니다. / 안녕. / 늦었 어 늦었 어 늦었 어
— 이상한 나라의 앨리스 (디즈니 버전, 1951)
생성자가 언제 호출 될 것인지 (객체 선언에서), 해당 소멸자가 언제 호출 될 것인지 (스코프 종료시) 알고 있으므로 한 줄만 사용하여 거의 마법 같은 코드를 작성할 수 있습니다. C ++ 원더 랜드에 오신 것을 환영합니다 (적어도 C ++ 개발자의 관점에서는).
예를 들어, 위의 잠금 객체가 사용 된 것처럼 카운터 객체를 작성하고 (실습으로 사용하겠습니다) 변수를 선언하여 사용할 수 있습니다.
void foo()
{
double timeElapsed = 0 ;
{
Counter counter(timeElapsed) ;
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
물론 매크로를 사용하여 Java / C # 방식으로 다시 작성할 수 있습니다.
void foo()
{
double timeElapsed = 0 ;
COUNTER(timeElapsed)
{
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
3. 왜 C ++가 부족 finally
합니까?
[SHOUTING] 마지막 카운트 다운입니다!
— 유럽 : The Final Countdown (죄송합니다. 여기에 인용문이 없습니다. :-)
이 finally
절은 C # / Java에서 범위 종료시 ( return
또는 throw 된 예외를 통해) 리소스 폐기를 처리하는 데 사용됩니다 .
예리한 사양 독자라면 C ++에 finally 절이 없음을 알게 될 것입니다. 그리고 이것은 RAII가 이미 자원 폐기를 처리하기 때문에 C ++에서 필요하지 않기 때문에 오류가 아닙니다. (그리고 C ++ 소멸자를 작성하는 것이 올바른 Java finally 절이나 C #의 올바른 Dispose 메서드를 작성하는 것보다 훨씬 쉽습니다).
그래도 때로는 finally
절이 멋질 것입니다. C ++로 할 수 있습니까? 응 우리는 할 수있어! 그리고 RAII를 번갈아 사용합니다.
결론 : RAII는 C ++의 철학 그 이상입니다. C ++입니다.
RAII? 이것은 C ++입니다 !!!
— 모호한 스파르타 왕과 그의 300 명의 친구들이 뻔뻔하게 복사 한 C ++ 개발자의 분노한 댓글
당신이 C에서의 경험을 어떤 수준에 도달하면 ++, 당신의 측면에서 생각을 시작 RAII 의 관점에서, 실행을 자동화 construtors와 소멸자 .
당신의 관점에서 생각하기 시작 범위 및 {
및}
문자가 코드에서 가장 중요한 요소 중 하나가됩니다.
그리고 거의 모든 것이 RAII 측면에서 적합합니다 : 예외 안전, 뮤텍스, 데이터베이스 연결, 데이터베이스 요청, 서버 연결, 시계, OS 핸들 등 그리고 마지막으로 중요한 것은 메모리입니다.
데이터베이스 부분은 무시할 수 없습니다. 가격을 지불하면 " 트랜잭션 프로그래밍 "스타일로 작성하여 최종적으로 모든 변경 사항을 커밋 할 것인지 결정할 때까지 코드 줄과 줄을 실행할 수 있습니다. , 또는 가능하지 않은 경우 모든 변경 사항을 되 돌리십시오 (각 줄이 최소한 강력한 예외 보장을 충족하는 한). ( 트랜잭션 프로그래밍에 대해서는 이 Herb 's Sutter 기사의 두 번째 부분을 참조하십시오 ).
그리고 퍼즐처럼 모든 것이 맞습니다.
RAII는 C ++의 많은 부분이므로 C ++가 없으면 C ++가 될 수 없습니다.
이것은 경험이 풍부한 C ++ 개발자가 RAII에 매료 된 이유와 RAII가 다른 언어를 시도 할 때 가장 먼저 검색하는 이유를 설명합니다.
그리고 Garbage Collector는 그 자체로 훌륭한 기술이지만 C ++ 개발자의 관점에서 그다지 인상적이지 않은 이유를 설명합니다.
- RAII는 이미 GC가 처리하는 대부분의 케이스를 처리합니다.
- GC는 순수 관리 개체에 대한 순환 참조를 사용하여 RAII보다 더 잘 처리합니다 (약한 포인터의 현명한 사용으로 완화됨).
- 여전히 GC는 메모리로 제한되지만 RAII는 모든 종류의 리소스를 처리 할 수 있습니다.
- 위에서 설명한 것처럼 RAII는 훨씬 더 많은 일을 할 수 있습니다.