【问题标题】:Pointer to generic type指向泛型类型的指针
【发布时间】:2010-10-22 01:31:55
【问题描述】:

在将给定的高效的基于指针的哈希映射实现转换为通用哈希映射实现的过程中,我偶然发现了以下问题:

我有一个代表哈希节点的类(哈希映射实现使用二叉树)

THashNode <KEY_TYPE, VALUE_TYPE> = class
public
  Key      : KEY_TYPE;
  Value    : VALUE_TYPE;
  Left     : THashNode <KEY_TYPE, VALUE_TYPE>;
  Right    : THashNode <KEY_TYPE, VALUE_TYPE>;
end;

除此之外,还有一个函数应该返回一个指向哈希节点的指针。我想写

PHashNode = ^THashNode <KEY_TYPE, VALUE_TYPE>

但这不能编译(';' 预期但 '

如何获得指向泛型类型的指针?

致 Barry Kelly:如果你读到这个:是的,这是基于你的哈希映射实现。您自己还没有编写过这样一个通用版本的实现,是吗?这样可以节省我一些时间:)

【问题讨论】:

    标签: delphi generics pointers delphi-2009 hashtable


    【解决方案1】:

    对不起,Smasher。不支持指向打开的泛型类型的指针,因为不支持泛型指针类型,尽管在某些情况下(特别是指向泛型类型内的嵌套类型的指针)可以(编译器错误)创建它们;如果我们破坏了某人的代码,则无法在更新中删除此“功能”。对泛型指针类型的限制应该在未来被取消,但我不能承诺什么时候。

    如果有问题的类型是我写的JclStrHashMap 中的类型(或古老的HashList 单元),那么重现它的最简单方法是将节点类型更改为类并传递任何双指针为Pointer,并进行适当的转换。但是,如果我今天再次编写该单元,我不会将存储桶实现为二叉树。我有机会在 Generics.Collections 单元中编写字典,尽管在交付可靠的 QA 之前,所有其他 Delphi 编译器的工作时间都太紧了,而且通用特性支持本身也在不断变化,直到相当晚。

    我更愿意将哈希映射存储桶实现为双重散列、每个存储桶的动态数组或连续数组中的单元格链接列表之一,以使用代表性数据进行测试的最佳结果为准。逻辑是树/列表中跟随链接的缓存未命中成本应该支配树和具有良好哈希函数的列表之间的桶搜索的任何差异。当前字典被实现为直线探测,主要是因为它相对容易实现并且可以使用可用的原始通用操作集。

    也就是说,二叉树存储桶应该是对不良哈希函数的有效对冲;如果它们是平衡二叉树(=&gt; 甚至更多的修改成本),它们的平均 O(1) 和 O(log n) 最坏情况下的性能。

    【讨论】:

    • +1 感谢您提供详细的 cmets!我在谈论 HashList 单元(在 codegear 论坛的某个地方找到它)。我将针对我的使用场景对二叉树与动态数组实现的效率进行一些测试。或者我只是等待关于 TDictionary 的更新。
    • 按照您的建议,我使用桶列表的动态数组实现了我的哈希列表类。只要合理选择哈希大小,性能就和以前一样好(由于显而易见的原因,去除甚至更好)。感谢您的帮助!
    【解决方案2】:

    如果 Delphi 完全支持泛型指针类型,它必须看起来像这样:

    type
      PHashNode<K, V> = ^THashNode<K, V>;
    

    也就是说,在声明类型名称的左侧提及泛型参数,然后在右侧构造类型时使用这些参数。

    但是,Delphi 支持。见QC 66584

    另一方面,我也质疑拥有一个指向类类型的指针的必要性。通用与否。他们只是非常很少需要。

    【讨论】:

    • 用于 FindNode (const Key : KEY_TYPE) : PHashNode 函数,这样就可以写成 Node := FindNode (Key);节点:= THashNode.Create;在原始版本中,它是一个双指针 PPHashNode。
    【解决方案3】:

    要真正回答您的问题,您不能创建指向泛型类型的指针,因为“泛型类型”不存在。您必须创建一个指向特定类型的指针,并填写类型参数。

    不幸的是,编译器不喜欢在 ^ 之后查找尖括号。但它会接受以下内容:

       TGeneric<T> = record
          value: T;
       end;
    
       TSpecific = TGeneric<string>;
    
       PGeneric = ^TSpecific;
    

    但是“PGeneric = ^TGeneric&lt;string&gt;;”给出了编译器错误。对我来说听起来像是一个小故障。如果我是你,我会向 QC 报告。

    你为什么要创建一个指向对象的指针呢? Delphi 对象是一种引用类型,因此它们已经是指针。您只需将对象引用转换为 Pointer 就可以了。

    【讨论】:

    • 甚至不必强制转换为指针。它已经是赋值兼容的。
    • 对于指针的必要性:请参阅我对 Rob 回答的评论。也许我可以避免它,但我只是在原始代码中翻译 PPHashNode...
    【解决方案4】:

    Generics.Collections 单元中有一个名为 TDictionary 的通用哈希映射。不幸的是,它目前已严重损坏,但显然将在更新 #3 中修复,该更新将在 within a matter of days, according to Nick Hodges 发布。

    【讨论】:

    • 我知道这个类,但我正在使用的实现(以及我想要转换)的好处是,它使用二叉树来存储桶列表,这使得存储量很大列表非常有效。从源代码中我可以看到,TDictionary 只是使用动态数组来存储桶列表。
    猜你喜欢
    • 2013-06-13
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 2022-11-18
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多