【问题标题】:Resource allocation and automatic deallocation资源分配和自动释放
【发布时间】:2010-05-25 12:40:31
【问题描述】:

在我的应用程序中,我得到了许多 class CDbaOciNotifier 实例。它们都共享一个指向 class OCIEnv 实例的指针。

我想要实现的是资源 class OCIEnv 的分配和释放将在 class CDbaOciNotifier 内自动处理。

期望的行为是,使用 class 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 之类的东西。

您认为我的问题有一个简单的解决方案吗?

【问题讨论】:

    标签: c++


    【解决方案1】:

    您的代码中发生了很多事情。这是解决方案,但只是简化为基本要素。

    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(静态初始化顺序未定义),您的应用可能会爆炸。

    【讨论】:

    • Caspin,非常感谢您的解释和代码示例。非常感谢。
    【解决方案2】:

    这对你有用吗?

    // 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);
    

    【讨论】:

    • 感谢您的回答,克里斯托。但这并没有显示出所需的行为。在您的示例中,将为应用程序创建一次 OCIEnv(它是静态的,所以这是预期的)。但是当 CDbaOciNotifier 的最后一个实例被销毁时,我不会被删除,而是在应用程序被卸载时。此外,循环 createEnvironment....freeEnvironment 可以在应用程序运行期间多次遍历。我在原始问题中添加了一个注释以进行澄清。
    猜你喜欢
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    相关资源
    最近更新 更多