模板类的智能指针?

Posted

技术标签:

【中文标题】模板类的智能指针?【英文标题】:Smart Pointer for a template class? 【发布时间】:2011-09-03 02:34:10 【问题描述】:

我怀疑我不能直接使用 PIMPL 模式执行此操作。是否可以有一个指向我无法通过转动shared_ptr 声明的旋钮进行编译。

// ============Foo.h ============
// Forward declare the implementation
template <typename T> class FooImpl;

class Foo

  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<T> > m_impl;
;

// ============FooImpl.h ============
template <typename T>
class FooImpl

    ...
;

在 Visual Studio 2008 下:“错误 C2065:'T':未声明的标识符”。我在 GCC 下收到类似的错误。 如果我取消对 FooImpl 的参数化(以便 FooTempl 继承自 FooImpl),代码将编译。

我怀疑我无法参数化智能指针,但我可能错了。

编辑:second Visual Studio 错误更能说明问题:“错误 C3203: 'FooImpl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a实型”

杰夫

【问题讨论】:

Tshared_ptr&lt;FooImpl&lt;T&gt;&gt; m_impl; 声明中是什么类型? Foo 应该是接受T 的模板吗? @silico: T 将是 Crypto++ 对象,例如 MD5、SHA1、SHA256 等哈希值。 您遇到什么错误? 总是发布编译器错误。 【参考方案1】:

我不完全确定您要完成什么,但这有帮助吗?

尝试1:

// ============Foo.h ============
// Forward declare the implementation

template <typename T> class FooImpl;

template<class C>
class Foo

  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<C> > m_impl;
;

// ============FooImpl.h ============
template <typename T>
class FooImpl

    ...
;

尝试2:

// ============Foo.h ============
// Forward declare the implementation

class FooImplBase;

class Foo

  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImplBase > m_impl;
;

// ============FooImpl.h ============
class FooImplBase 
  public:
    virtual void AnAPI();
    virtual int AnotherAPI();
;
template <typename T>
class FooImpl : public FooImplBase

    ...
;

【讨论】:

最后,我无法使用带有模板参数的智能指针,我不得不切换到 3 个类(该死的几乎与上面的数字 2 完全一样)。【参考方案2】:

您发布的代码无法编译,因为TFoo 的上下文中没有任何意义。编译器在这里需要一个名为 T 的类型,但那里不存在...不完全确定您要完成什么,但以下内容不能解决您的问题吗?

// ============Foo.h ============ 

class FooImplBase 
    virtual void WhateverFooImplIsSupposedToDo() = 0;
;

template <typename T> class FooImpl : public FooImplBase 
    T mInstance;
public:
    FooImpl(T const & pInstance) : mInstance(pInstance) 
    virtual void WhateverFooImplIsSupposedToDo() 
    
        // implementation which deals with instances of T
    
; 

class Foo 
 
  public: 
    Foo getInstance(const string& fooType) 
     // use m_impl->WhateverFooImplIsSupposedToDo...
        

    template < class T >
    Foo( T const & pInstance ) : m_impl(new FooImpl<T>(pInstance)) 
  private: 
    shared_ptr< FooImplBase > m_impl; 
; 

【讨论】:

从概念上讲,这与我想要的相似。但是,我不希望用户必须声明 Foo&lt;int&gt; f。我不得不删除参数化的智能指针,并使用 3 个类。 嗯,使用这种类型排列,您不必定义Foo&lt;int&gt;。您实际上不能,因为Foo 不是类模板...您的用户在调用站点编写Foo tTmp = 5; 之类的表达式或编写void TakeFoo(Foo const &amp; pF) 之类的函数或使用TakeFoo(123.5); 之类的表达式。这是否有意义取决于您想要实现的目标。【参考方案3】:

您做对了,只需确保已定义 T。这在 MSVC++ 2010 上为我编译:

#include <memory>

using namespace std;

template<class T>
class Blah 
public:
    Blah()  
;

class Foo 
public:
    shared_ptr<Blah<int>> ptr;

    Foo() : ptr(new Blah<int>())  
;

如果您使用的旧编译器尚未包含 C++11 的此功能,请更改

shared_ptr<Blah<int>> ptr;

shared_ptr<Blah<int> > ptr;

所以编译器不认为&gt;&gt; 是右移。不过 C++11 没有这个问题。

【讨论】:

好的。让我回到它(我一直在使用 FooImpl 类的前向声明来研究 GCC)。 我事先不知道我会有一个 Blah,只有一个 Blah @noloader 是的,我知道,只需将 Foo 设为模板即可。 我想这样做,但这妨碍了它在客户端代码中的使用。我希望用户能够做到Foo f = Foo::getInstance(...) @noloader 如果Foo 是模板,则Foo f = ... 无效。对于某些T,它必须Foo&lt;T&gt; f = ...【参考方案4】:

我事先不知道我会有一个 Blah,只有一个 Blah。

从语言的角度来看,Blah&lt;T&gt; 没有意义,因为T 不存在。根据您的具体目标,您可以

Foo也做成一个模板,这样你就可以声明一个模板参数T

template<typename T>
class Foo

  public:
    Foo getInstance(const string& fooType);
    ...
  private:
    shared_ptr< FooImpl<T> > m_impl;
;

当您声明Foo&lt;T&gt; 类型的变量时,它“修复”了T 的选择;

或使FooImpl 明确派生自一个公共基础:

class FooBase 
    // need to define the interface here
;

// this is a class definition whereas previously you only needed a declaration
template<typename T>
class FooImpl: public FooBase 
    // definition here
;

class Foo

  public:
    Foo getInstance(const string& fooType);

    // we needed the definition of FooImpl for this member
    // in addition this member is quite obviously a template
    template<typename T>
    void
    set(FooImpl<T> const& foo)
    
        m_impl.reset(new FooImpl<T>(foo));
    

    // not a member template!
    void
    use()
    
        // any use of m_impl will be through the FooBase interface
    

  private:
    shared_ptr<FooBase> m_impl;
;

对于给定的Foo 实例,可以动态设置任何类型的FooImpl&lt;T&gt;,然后通过FooBase 接口使用。这是一种type erasure,因为它在 C++ 世界中被称为。

【讨论】:

【参考方案5】:

我们可以使用模板来编写一个通用的智能指针类。以下 C++ 代码演示了相同的内容。我们不需要调用 delete 'ptr',当对象 'ptr' 超出范围时,它的析构函数会自动进行。

#include<iostream>
using namespace std;

// A generic smart pointer class
template <class T>
class SmartPtr

   T *ptr;  // Actual pointer
public:
   // Constructor
   explicit SmartPtr(T *p = NULL)  ptr = p; 

   // Destructor
   ~SmartPtr() 
    cout <<"Destructor called" << endl;  
    delete(ptr);
   

   // Overloading dereferncing operator
   T & operator * ()   return *ptr; 

   // Overloding arrow operator so that members of T can be accessed
   // like a pointer (useful if T represents a class or struct or 
   // union type)
   T * operator -> ()  return ptr; 
;

int main()

    SmartPtr<int> ptr(new int()); // Here we can create any data type pointer just like 'int'
    *ptr = 20;
    cout << *ptr;
    return 0;

输出:

20

调用析构函数

【讨论】:

以上是关于模板类的智能指针?的主要内容,如果未能解决你的问题,请参考以下文章

shared_ptr智能指针模板类的简单实现(c++11)

再论智能指针(上)

智能指针的延伸两种定制删除器的实现方法

第十六章 String类和标准模板库(1. string类智能指针)

浅谈ObjectARX智能指针AcDbObjectPointer的用法

智能指针类模板