删除boost :: bind的原始指针参数

dim*_*mba 6 c++ memory-management auto-ptr boost-bind boost-function

假设我已经分配了堆A*,我希望将其作为参数传递给boost::bind. boost::bind保存以供稍后处理某些STL的容器boost::functions.

我想确保A*在销毁STL容器时销毁.

示范:

A* pA = new A();

// some time later
container.push_back(boost::bind(&SomeClass::HandleA, this, pA);

// some time later
container is destroyed => pA is destroyed too
Run Code Online (Sandbox Code Playgroud)

怎么做到呢?

编辑

也许我想要的不是那么现实.

我有原始指针和函数接收原始指针.通过boost :: bind延迟调用.此时我想要自动内存管理,以防boost :: bind想要执行.我很懒,所以我想使用"准备好"的智能指针解决方案.

std :: auto_ptr看起来像个好人,但是......

auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, pAutoA);
Run Code Online (Sandbox Code Playgroud)

不编译(见这里)

auto_ptr<A> pAutoA(pA);
container.push_back(boost::bind(&SomeClass::HandleA, this, boost::ref(pAutoA));
Run Code Online (Sandbox Code Playgroud)

pAutoA被破坏,删除了底层的pA.

编辑02

在上面提到的容器中,我将需要使用不同的参数存储misc"回调".其中一些是对象的原始指针.由于代码是旧的,我并不总是可以改变它.

编写自己的包装器来存储容器中的回调是最后的手段(可能是唯一的),因此是赏金.

Mar*_*utz 8

@pmjordan的想法已经朝着正确的方向发展.您回答说您无法使用shared_ptr,因为一旦构建,您就无法取回所有权.但这并不完全正确:使用shared_ptr自定义删除机制,你可以.这是如何:

为您Af(A*)以下假设这些玩具定义:

struct A {
    ~A() { std::cout << "~A()" << std::endl; }
};

void f( A * a ) {
    std::cout << "in f(A*)" << std::endl;
    delete a;
}
Run Code Online (Sandbox Code Playgroud)
  1. 写一个可以"关闭"的删除器:

    struct opt_delete {
        bool m_delete;
        opt_delete() : m_delete( true ) {}
        template <typename T>
        void operator()( T * t ) {
            if ( m_delete ) delete t;
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然后,您可以编写一个再次take()获取shared_ptr有效负载所有权的函数:

    template <typename T>
    T * take( const boost::shared_ptr<T> & sp ) {
        opt_delete * d = boost::get_deleter<opt_delete>( sp );
        assert( d );
        assert( d->m_delete == true );
        d->m_delete = false;
        return sp.get();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    (这将使剩余的shared_ptr实例中的有效负载,但对于您的情况,这没关系,并且assert()当不是时覆盖案例).

  3. 现在您可以f(A*)像这样手动换行:

    void f_sp( const boost::shared_ptr<A> & a ) {
        f( take( a ) );
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 最后,测试两种情况:

    int main( int argc, char * argv[] ) {
    
        const boost::shared_ptr<A> a( new A, opt_delete() );
    
        const boost::function<void()> func =
            boost::bind( &f_sp, a );
    
        if ( argc >= 2 && *argv[1] == '1' ) // call 'func'
            func();
        else
            ; // don't
    
        return 0;
    }
    
    Run Code Online (Sandbox Code Playgroud)

1将打印带有参数的测试程序

在f(A*)
~A()

如果没有(或任何其他参数),它将打印出来

〜A()

您可以将测试安全带扩展到先放入func容器,但它仍然是安全的.在这种情况下唯一不安全的是func不止一次调用副本(但之后你会触发第二个断言take()).

编辑:请注意,此机制不是线程安全的.为了使线程安全的,你需要提供opt_delete一个互斥体同步operator()使用take().