【问题标题】:Can I abstract away specific details about templated classes?我可以抽象出有关模板类的特定细节吗?
【发布时间】:2015-04-04 18:45:46
【问题描述】:

我正在努力在 C++11 中创建一个工厂库(类似于可用于 Java 的 https://github.com/google/guice),以熟悉模板编程,并创建一个有用的依赖减少工具。这个想法是工厂将抽象出对象的创建和销毁的细节,并隐藏实现细节。理想情况下,我想要类似的东西:

InterfaceClass
{
    public:
    virtual void doSomething () = 0;
    virtual ~InterfaceClass () {};
}

// Might need custom deleter depending on how the class was allocated
// (might come from a pool, etc)
ImplementationClass : public InterfaceClass
{
    public:
    // Some (possibly) complicated constructor.
    ImplementationClass(Dependency one, Other dependency) {}

    virtual void doSomething ()
    {
        // Implementation
    }

    virtual ~ImplementationClass ()
    {

    }
}

理想情况下,我希望图书馆的最终用户能够(或类似的东西):

std::unique_ptr<InterfaceClass> object = factory<InterfaceClass>();

如果所有类都使用默认删除器,这将非常有用,但在自定义删除器的情况下,unique_ptr 的类型将从:

std::unique_ptr<I> 

到:

std::unique_ptr<I, deleter> 

——据我所知,这些类型不兼容。

有没有一种方法可以定义某种更高级别的“唯一指针”,它不关心其类型签名中的删除器?使 API 与对象的创建/删除无关的其他可能解决方法?

谢谢!

【问题讨论】:

  • 您的课程需要自定义删除器来做什么?虚拟析构函数以何种方式不足以自定义清理?
  • 我想到了一个这样的用例:当获取一个对象时,它可能来自一个预先分配的内存池。在这种情况下,我不想让 unique_ptr 释放该内存。创建它的池可能希望保留可用块的计数,在这种情况下删除只是将块标记为再次可用。
  • 大概是工厂知道这些细节吧。所以让它返回适当的unique_ptr 专业化;调用者可以使用auto 来避免拼写类型。或者,使用shared_ptr 代替unique_ptr - 使用shared_ptr,自定义删除器不是类型的一部分。
  • 感谢@igor 的关注——我想避免使用auto,因为这实际上不允许这两种类型相互兼容。它只是避免了输入差异。我个人也发现使用 auto 会使对象的类型更难追踪。

标签: c++ templates c++11 factory unique-ptr


【解决方案1】:

使用std::function 拥有一个通用的类型擦除删除器。

Ideone link

#include <iostream>
#include <memory>
#include <functional>

template<typename T>
using TypeErasedUPtr = std::unique_ptr<T, std::function<void(T*)>>;

int main() 
{
    TypeErasedUPtr<int> p1{new int(5), [](int* x){ delete x; }};
    TypeErasedUPtr<int> p2{someAllocator<int>(5), [](int* x){ someDeallocator(x); }};

    // `p1` and `p2` have the same type, `TypeErasedUPtr<int>`.

    return 0;
}

这是可行的,因为std::unique_ptr&lt;T, TDeleter&gt; 采用任何可以使用T* 参数调用的可调用TDeleter 类型。

std::function&lt;void(T*)&gt; 满足该要求,并在运行时使用该签名多态地包装任何类型的函数(通过支付少量运行时开销价格)。

【讨论】:

  • 谢谢!这正是我需要的。 TypeErasedUPtr 也能够在没有第二个模板参数的情况下接受std::unique_ptr&lt;&gt;(或者更确切地说,同时使用显式和隐式参数)。
【解决方案2】:

您始终可以包装需要自定义删除器的类型。实际上,您应该这样做,因为自定义删除器是您不希望公开的实现细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    相关资源
    最近更新 更多