【问题标题】:c++ Destructor with templates: T could be a pointer or notc++ 带模板的析构函数:T 可以是指针,也可以不是
【发布时间】:2014-05-15 21:10:03
【问题描述】:

我在编写模板类 win C++ 时遇到了一个小问题。 问题很简单:我不知道是否对参数化类型执行delete,因为它可以是,也不能是指针。

我看过这个:Destructor in template class c : How to delete field which may be pointer or not pointer?

我已经实现了第一个解决方案,但这需要我专攻整个班级,所以这意味着我必须有 2 个班级:

template<class T>
class Node {
private:
    T _content;
public:
    Node(const T c); 
    ~Node();
};

template<class T>
class Node<T*> {
private:
    T _content;
public:
    Node(const T c); 
    ~Node();
};

我只想要第二个版本并专门析构函数如下:

template<class T>
class Node<T*> {
private:
    T _content;
public:
    Node(const T c); 
    ~Node();
};
template <class T>
Node<T>::~Node() {
    while(!_adjacent.isEmpty()) {
        disconnectFrom(_adjacent.first());
    }
}
template <class T>
Node<T*>::~Node() {
    while(!_adjacent.isEmpty()) {
        disconnectFrom(_adjacent.first());
    }
    delete _content;
}

然后我收到以下错误:

Node.hpp:43:17: error: invalid use of incomplete type ‘class Node<T*>’
Node.hpp:8:7: error: declaration of ‘class Node<T*>’

有没有办法只专门化构造函数以避免有 2 个类(我的 Node 类比我在这里展示的要大得多)?

谢谢!

【问题讨论】:

  • 你能更清楚地解释一下你想专攻什么方法吗?不,你不能部分特化函数模板和类模板的方法(构造函数和析构函数都是方法,所以......)。
  • 为什么不使用 unique_pointer 而不是原始指针?没有开销,它会随心所欲。

标签: c++ templates pointers


【解决方案1】:

一种解决方案是使用特征类:

template<typename T> struct delete_traits
{
  void destroy(T&) {}
};

template<typename T> struct delete_traits<T*>
{
  void destroy(T* p) { delete p; }
};

然后在你的类析构函数中写

delete_traits<T>::destroy(_contents);

除了不必专门化 Node 模板之外,它还有一个额外的优势,即您可以轻松添加其他方式来破坏事物,而无需触及您在其中定义的文件 Node,只需添加另一个模板专门化:

// assumes that mylib_handle is a truly different type, maybe a C struct
// from the C interface of a library
template<> struct delete_traits<mylib_handle>
{
  void destroy(mylib_handle& h) { mylib_handle_free(m); }
};

【讨论】:

  • 坏主意,因为现在节点 总是 拥有 T 背后的任何东西。没必要。另外,您如何区分使用 new、new[]、malloc、SysString 等分配的 char*?
  • 这是请求的功能。你最好在那里讨论这是否是一个坏主意。我只是展示了如何实现它。
  • 据我了解,需要一个特定的功能:能够专门化模板以供拥有/非拥有使用。此外,还展示了提问者想法的部分实现,并且它没有按预期工作。指出他做错事是恕我直言。
  • 嗯,我按照我的回答方式阅读了请求。无论如何,指出想要是一件坏事当然是一个好主意,如果对合适的人这样做(出于这个原因,我赞成你对这个问题的回答)。但是,如果您愿意,请说明如何做到这一点,恕我直言,这也是一件有效的事情,特别是因为该技术是通用的,并且不限于此特定问题。
  • 是的。是的!这当然不是一个完美的解决方案——你可能会遇到各种麻烦——但它对我的特定用例有用,我非常感谢它。谢谢。
【解决方案2】:

根本不要专门化Node。只需为您的意图使用正确的类型:

  • 独资:std::unique_pointer&lt;T&gt;
  • 共享所有权:std::shared_pointer&lt;T&gt;
    • 共享所有权的反向链接:std::weak_pointer&lt;T&gt;
  • 无所有权:原始指针

如果您需要特定的析构函数,这些模板有一个参数。
此外,您可以将它们用于句柄等,即使它们没有命名为指针。

【讨论】:

  • 所以,你是说我应该总是有一个指针?无论是原始指针还是其中一个智能指针,都可以吗?
  • 是的。标准库可供使用,组合是一个有价值的工具。
【解决方案3】:

看来你想要这个:

template<class T>
class Node {
private:
    T _content;
public:
    Node(const T c) : _content { c } {}
    ~Node() {}
};

template<class T>
class Node<T*> {
private:
    T* _content;
public:
    Node(const T* c) : _content { c } {}
    ~Node() { delete _content; }
};

而且,正如@Constructor 所说,不,你不能只专门化析构函数,你必须做整个类......但如果类更大,你可以将共性重构为基类,然后你' d 有类似的东西:

template<class T>
class BaseNode {
private:
  template<class> friend class Node;
    T _content;
public:
    BaseNode(T c) : _content { c } {}
    ~BaseNode() {}
};

template<class T>
struct Node : BaseNode<T> {
  Node(T c) : BaseNode<T>(c) {};
  ~Node() {}
};

template<class T>
struct Node<T*> : BaseNode<T*> {
  Node(T* c) : BaseNode<T*>(c) {};
  ~Node() { delete BaseNode<T*>::_content; }
};

【讨论】:

  • 谢谢。我想过,但我试图避免这种情况......我认为代码看起来更混乱......;)
猜你喜欢
  • 2023-01-01
  • 2011-02-11
  • 2012-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2020-11-22
  • 1970-01-01
相关资源
最近更新 更多