使用任意拥有指针而不进行模板化

时间:2013-05-28 17:28:10

标签: c++ c++11 shared-ptr smart-pointers

我想将对象的所有权(共享)传递给函数foo::bar。 事情是我不在乎,所有权是独占还是共享。 我将class foo视为一个界面,我不想关心所有权细节。 我所关心的是,我可以确保传递的智能指针的生命周期超过foo::bar的返回值。

现在我可以写

class foo {
  void bar( std::shared_ptr<blub> );
  void bar( std::unique_ptr<blub> );
};

但是在我们积累了几个智能指针变体的时候,这是不优雅的。 为每个变体写一个重载是非常麻烦的,特别是如果我想在我的代码中多次使用这个方案。

现在我也不希望foo被模板化,因为明显的模板复杂性。

我能想到的最简单的是智能指针包装器

template <typename T>
class owning_ptr {
  // Sorts out the largest type so we can allocate enough space
  typedef largest<std::shared_ptr<T>, std::unique_ptr<T>, myptr<T>>::type big_type;
  typedef std::aligned_storage <sizeof(big_type), std::alignment_of<big_type>::value>::type buffer_type;
  buffer_type _internal;
  int _type;
};

这有点低效。有没有更好的方法来构造包装器?

最后我真的想签名:

class foo {
  void bar( owning_ptr<blub> );
};

1 个答案:

答案 0 :(得分:0)

注意:底部有一个有趣的编辑

如果您不想对拥有的指针类型进行参数化或重载,那么您最好采用shared_ptr<>并强制转换unique_ptr<>。我能想到的任何非模板解决方案至少具有与shared_ptr相同的开销,大多数需要多态调用,免费存储分配,或两者兼而有之。

您可以通过采用某种类型的代理转换器从shared_ptr自动转换,这样您就可以使用unique_ptr R值或shared_ptr而无需转换或显式转换(move()除外)并提取可用的shared_ptr以存储在您的实例中。这是一个例子:

#include <iostream>
#include <memory>
#include <utility>
using namespace std;

// Take an instance of gimme_owned_ptr<T> to save off a shared_ptr<T>
// from either a shared_ptr or unique_ptr.
template<typename T>
struct gimme_owned_ptr {
    // Make the two constructors templates so we can accept
    // any convertible owning pointer:
    template<typename S>
    gimme_owned_ptr( unique_ptr<S> p )
        : p_( shared_ptr<S>( move(p) ) )
    { }
    template<typename S>
    gimme_owned_ptr( shared_ptr<S> p )
        : p_( p )
    { }
    shared_ptr<T> get() const {
        return p_;
    }
private:
    shared_ptr<T> p_;
};

struct Foo {
    void operator()() const { v_call(); }
    virtual ~Foo() { }
private:
    virtual void v_call() const = 0;
};

struct Bar {
    Bar( gimme_owned_ptr<Foo const> const &gop )
        : foo_( gop.get() )
    { }
    void operator()() const { (*foo_)(); }
private:
    shared_ptr<Foo const> foo_;
};

struct Baz : Foo {
private:
    virtual void v_call() const { cout << "Baz()()\n"; }
};

int main() {
    unique_ptr<Baz> upf( new Baz() );
    shared_ptr<Baz> spf( new Baz() );

    Bar upb( move( upf ) );
    Bar spb( spf );

    upb();
    spb();
}

是的,此解决方案确实使用模板,但仅适用于gimme_owned_ptr实用程序类模板,仅用于重复使用和转换。您自己的类(在这种情况下为Bar)不需要是模板,也不需要重新实现gimme_owned_ptr以将其用于其他类型。

========编辑========

我刚检查过,从unique_ptrshared_ptr的内置转换基本上完成了我上面写的gimme_owned_ptr类的所有内容。如果该类采用shared_ptr<T>类型,则传递move(unique_ptr<S>)将导致可行的转换。所以,你真正需要的只是shared_ptr,而用户唯一需要做的就是在move()上调用unique_ptr(无论如何他们都应该这样做)。使用类似gimme_owned_ptr之类的东西的唯一原因是接受不同的指针混合或以不同的方式接受它们。 (例如,您可以通过move()并在内部调用unique_ptr<S>&来使move()不必要,但这可能是一个坏主意,因为它会默默地占有所有权。)