2009-09-22 4 views
7

RAII 스타일의 C++ 클래스가 있다고 가정 해 보겠습니다.RAII 스타일의 클래스가 "익명으로"인스턴스화되는 것을 방지 할 수 있습니까?

class StateSaver 
{ 
    public: 
    StateSaver(int i) { saveState(); } 
    ~StateSaver() { restoreState(); } 
}; 

... 내 코드 에서처럼 사용할 수 있습니다.

void Manipulate() 
{ 
    StateSaver save(1); 

    // ...do stuff that modifies state 
} 

... 어떤 상태로 들어가는 것이 목표입니까? 그 범위를 떠나면 그 상태로 두십시오. 이 오타를 컴파일하지 못하게하는 방법이 있습니까 (또는 경고하거나 어떻게 불만을 제기하여 실수를 알 수 있습니까)?

void Manipulate() 
{ 
    StateSaver(1); // ruh-roh, state saved and immediately restored! 

    // ...do stuff that modifies state 
} 

나는 C++에서이 문제를 방지하기 위해 사용할 수있는 것을 전혀 모르고 있지만, 그것이 존재하지 않는다는 것을 의미하지는 않습니다. C++에 아무 것도 없으면 컴파일러에 특정한 확장이 허용 될 것입니다. 나는 gcc와 msvc (언젠가 icc, 다른 컴파일러에 대한 아이디어가 유용 하겠지만 덜 유용 할 것입니다)를 목표로하는 것에 관심이 있습니다. 그래서 그들 중 하나의 해킹이 유용 할 것입니다 (적절하게 #defdef 된 매크로 정의로 추상화됩니다) .

+0

SaveMatrix() -> 나 함수 호출처럼 보인다. –

+0

SaveMatrix save() : -> 나에게 함수 선언처럼 보입니다. –

답변

3

I을 다음과 같이이 다음 작동

class RAII 
{ 
public: 
    bool valid; 
    RAII() 
     : valid(false) 
    { 
     cout << "RAII ctor" << endl; 
    } 

    void Do() 
    { 
     valid = true; 
    } 

    ~RAII() 
    { 
     assert(valid); 
     cout << "RAII dtor" << endl; 
    } 
}; 

을 왈도 게시 변형에서 방법의 무리에 my solution을 조정할했다,하지만 난 결국에 도착하는 것은의 매크로화된 버전 :

class GuardNotifier 
{ 
    bool* notified; 
    public: 
    GuardNotifier() : notified(NULL) { } 
    void init(bool* ptr) { notified = ptr; } 
    ~GuardNotifier() { *notified = true; } 
}; 
class GuardNotifyReceiver 
{ 
    bool notified; 
    public: 
    GuardNotifyReceiver() : notified(false) { } 
    void init(const GuardNotifier& notifier) 
     { const_cast<GuardNotifier&>(notifier).init(&notified); } 
    ~GuardNotifyReceiver() { assert(notified); } 
}; 
class StateSaver 
{ 
    GuardNotifyReceiver receiver; 
    public: 
    StateSaver(int i, 
       const GuardNotifier& notifier = GuardNotifier()) 
    { 
     receiver.init(notifier) 
     saveState(); 
    } 
    ~StateSaver() 
    { 
     restoreState(); 
    } 
}; 
6

SaveMatrix save();도 개체를 정의하지 않습니다. 함수를 선언합니다.

다른 사람 (또는 너 자신, FTM)이 원하는 것 외에 다른 일을하지 못하게하는 방법은 거의 없습니다. 내가 생각할 수있는 유일한 것은 코드 자체를 작성하는 것이 아니라 매크로를 쓰는 것입니다.

#define SAVE_MATRIX SaveMatrix save ## __LINE__ 

그러나 이것은 매우 추합니다. OTOH, 컴파일 타임에 오류를 잡아냅니다.

9

컴파일 타임에 아무 것도 할 수 있는지 잘 모르겠습니다. 런타임 체크를 들어, 당신이 할 수 있습니다 :

SaveMatrix sm(sm); 

을 임시을 위해 동일한 작업을 수행 할 수있는 방법은 식별자에 바인딩없이 없다 : 클라이언트가 필요

struct SaveMatrix 
{ 
    SaveMatrix(const SaveMatrix& that) { 
     assert(this == &that); 
     glPushMatrix(); 
    } 
    ~SaveMatrix() { glPopMatrix(); } 
}; 

작성 (어떤 점에서 그것은 자동 변수와 다르지 않다).

+2

처음에는 조금 이상하게 보였지만 RAII-idiom의 일부가 될 수 있습니다. 질문이 C++/RAII의 실제 문제를 보여주기 때문입니다. 차라리 내 자물쇠가 작동하지 않는다는 사실을 알아내는 것보다 조금 더 뻔뻔 스러울 것입니다. – stefaanv

+0

흠, 내가 좋아하는 옵션이 최고라고 생각합니다.아주 자연스럽지는 않지만 RAII 자체는 적어도 클래스를 주로 초기화와 정리로 구조체라고 생각하지 않는 한 자연스럽지 않습니다. 감사! –

1

클래스는 임시 (SaveMatrix()) 또는 변수 (SaveMatrix save;)로 인스턴스화되었는지 알 수 없습니다. 나는 가장 좋은 방법은하고있는 프로그래머를 중지 생각 스택 또는 매크로 해킹 건설 후 멤버 함수 호출, 예를 들어 강제로하지 않고 : 실제로

{ 
    // Intended use 
    RAII raii; 
    raii.Do(); 

    cout << "Some task" << endl; 
} 

{ 
    // Woops: forgot Do() 
    RAII raii; 

    cout << "Some task" << endl; 
} 

{ 
    // Woops: forgot Do() 
    RAII(); 

    cout << "Some task" << endl; 
} 

{ 
    // Programmer shot self in foot, hopefully the act of typing this would make them realise that 
    RAII().Do(); 

    cout << "Some task" << endl; 
} 
+1

'RAII(). Do()'는 실패하지 않습니다. AFAIU, Op는 머피 녀석이 아니라 마키아 벨리를 셧아웃하려고합니다. – sbi

관련 문제