2010-05-25 5 views
2

내 응용 프로그램에서 클래스 CDbaOciNotifier의 많은 인스턴스가 있습니다. 모두 클래스 OCIEnv 클래스의 하나의 인스턴스에 대한 포인터를 공유합니다.리소스 할당 및 자동 할당 해제

는 내가 달성하고자하는 것은이 클래스 CDbaOciNotifier 내부에서 자동으로 처리됩니다 OCIEnv 자원 클래스의 할당 및 할당 취소합니다.

클래스 CDbaOciNotifier의 첫 번째 인스턴스에서 환경이 생성되고 이후의 모든 알리미는 동일한 환경을 사용합니다. 마지막 알리미가 파기되면 환경도 파괴됩니다 (사용자 정의 삭제 자 호출). 나중에이주기는 새로운 환경을 만들면서 다시 시작할 수 있습니다.

#pragma once 

#include <string> 
#include <memory> 
#include "boost\noncopyable.hpp" 

class CDbaOciNotifier : private boost::noncopyable 
{ 
public: 

    virtual ~CDbaOciNotifier(void); 

    static std::auto_ptr<CDbaOciNotifier> createNotifier(const std::string &tnsName, const std::string &user, const std::string &password); 

private: 
    CDbaOciNotifier(OCIEnv* envhp); 

    // All notifiers share one environment 
    static OCIEnv* m_ENVHP; 

    // Custom deleter 
    static void freeEnvironment(OCIEnv *env); 

    OCIEnv* m_envhp; 
}; 

CPP : (신고자를 만드는 정적 팩토리 메소드를 사용하여) 내가 지금까지있어 무엇

#include "DbaOciNotifier.h" 

using namespace std; 

OCIEnv* CDbaOciNotifier::m_ENVHP = 0; 

CDbaOciNotifier::~CDbaOciNotifier(void) 
{ 
} 

CDbaOciNotifier::CDbaOciNotifier(OCIEnv* envhp) 
       :m_envhp(envhp) 
{ 

} 

void CDbaOciNotifier::freeEnvironment(OCIEnv *env) 
{ 
    OCIHandleFree((dvoid *) env, (ub4) OCI_HTYPE_ENV); 
    *env = null; 
} 

auto_ptr<CDbaOciNotifier> CDbaOciNotifier::createNotifier(const string &tnsName, const string &user, const string &password) 
{ 
    if(!m_ENVHP) 
    { 
     OCIEnvCreate((OCIEnv **) &m_ENVHP, OCI_EVENTS|OCI_OBJECT, (dvoid *)0, 
      (dvoid * (*)(dvoid *, size_t)) 0, 
      (dvoid * (*)(dvoid *, dvoid *, size_t))0, 
      (void (*)(dvoid *, dvoid *)) 0, 
      (size_t) 0, (dvoid **) 0); 
    } 

    //shared_ptr<OCIEnv> spEnvhp(m_ENVHP, freeEnvironment); ...got so far... 

    return auto_ptr<CDbaOciNotifier>(new CDbaOciNotifier(m_ENVHP)); 
} 

을 내가 참조 (신고자)을 계산하지 않도록하고 싶습니다 shared_ptr과 같은 것을 사용하십시오.

내 문제는 쉽게 해결할 수 있습니까?

답변

2

코드에 많은 부분이 있습니다. 여기에 해결책이 있지만 단순한 필수 요소로 단순화되었습니다.

class CDbaOciNotifier 
{ 
public: 
    CDbaOciNotifier() : 
     m_resource(get_env()) 
    { } 

private: 
    shared_ptr<OCIEnv> m_env; 

    struct Delete_env 
    { 
     void operator()(OCIEnv* env) 
     { 
     OCIHandleFree(...); 
     } 
    }; 

    static shared_ptr<OCIEnv> get_env() 
    { 
     // make sure a mutex is involved if CDbaOciNotifier 
     // can be constructed concurrently. 

     static weak_ptr<OCIEnv> s_env; 

     shared_ptr<OCIEnv> env = s_env.lock(); 
     if(! env) 
     { 
      OCIEnv* env_ptr = OCIEnvCreate(...); 
      env.reset(env_ptr, Delete_env()); 
      s_env = env; 
     } 
     return env; 
    } 
}; 

작성한대로 CDbaOciNotifier을 동시에 작성할 수 없습니다. 그 능력을 원한다면 s_env을 보호하기 위해 정적 뮤텍스가 필요합니다.

weak_ptr은 로컬 함수입니다. 그렇지 않으면 전역 또는 정적 CDbaOciNotifier이 생성되면 (정적 초기화 순서가 정의되지 않음) 앱이 폭발 할 수 있습니다.

+0

Caspin, 설명과 코드 예제에 감사드립니다. 나는 그것을 매우 고맙게 생각한다. – nabulke

1

이 기능이 유용합니까?

// In .h file 
class CDbaOciNotifier 
{ 
    // ... 
    private: 
     static shared_ptr<OCIEnv> envPtr; 
}; 

// In .cpp file 
// Write freeEnvironment as a free function. 
shared_ptr<OCIEnv> CDbaOciNotifier::envPtr(new OCIEnv, freeEnvironment); 
+0

답변 해 주셔서 감사합니다. Kristo. 그러나 이것은 필요한 행동을 보여주지 않습니다. 예제에서 OCIEnv는 애플리케이션에 대해 한 번 생성됩니다 (정적이므로 예상 한 것임). 하지만 CDbaOciNotifier의 마지막 인스턴스가 삭제되었지만 응용 프로그램이 언로드 될 때 나는 삭제되지 않을 것입니다. 또한주기 createEnvironment .... freeEnvironment는 응용 프로그램 실행 중 여러 번 탐색 할 수 있습니다. 내가 원래의 질문에 설명을 추가했습니다. – nabulke