通用类库 - 错误、说明、问题、使用功能和建议 - 页 29

 
Alexey Volchanskiy:

MSDN称它为环形缓冲器,这个名字不是我想出来的。

链接到

阿列克谢-纳沃伊科夫

...并以通过引用而不是仅仅通过值来转换参数而结束。

在字面上可能有问题

 
TheXpert:

在工作室的链接。

在字面上可能有一个问题

懒得再去搜索那篇文章,但我已经把它拉长了一些。环状单链表或双链表是以链表为基础的,但最后一个元素存储了一个与第一个元素的链接。

 
TheXpert:

在字面上可能有问题

不,我的 "数值 "类继承自基础的 "引用 "类,纯粹是作为一个包装器。因此,只需选择所需的类的版本,然后去
 
Alexey Volchanskiy:

单链表或双链表是以链表为基础的,但链表中的最后一个项目存储了一个与第一个项目的链接。

这就是重点:它是一个 "基础",而不是一个替代。 没有人阻止开发者在这里也把它作为一个额外的容器。而不是用普通的概念来代替
 
Alexey Navoykov:

最有可能的是,移植这些类的人只是决定通过简化代码来简化他的生活。 他没有用两个指针m_first和m_last,而是用一个指针m_head。

看了一下dotnet的源代码,发现了原因。 LinkedList类本身是被正确移植的,实际上只有一个指针头,它既是起点也是终点。所以内部实现确实是循环的,但外部行为却不是。 MQ在CLinkedNode类(Next和Previous方法)中出现了错误。 下面是其原始实现的样子。

        public LinkedListNode<T>? Next
        {
            get { return next == null || next == list!.head ? null : next; }
        }

        public LinkedListNode<T>? Previous
        {
            get { return prev == null || this == list!.head ? null : prev; }
        }

而这里是如何移植到MQL的。

   CLinkedListNode<T>* Next(void)                      { return(m_next); }
   CLinkedListNode<T>* Previous(void)                  { return(m_prev); }

也许他们注意力不集中,弄错了。

但总的来说,我对dotnet的实现也有点惊讶。 为什么不可能在列表本身中做两个指针(第一个和最后一个)而不是一个头。这将避免在列表节点的上述方法中进行额外的检查,也就是说,它们看起来和现在的MQ一模一样,但一切都会正常工作。 当然,这将减缓节点插入/删除的过程,但它将加快对它们的迭代,这是一个更高的优先级。 下一个和上一个肯定被更频繁地调用,而不是添加节点。 我就是这样做的,我以为Melkomsoft也会这样做。 但不要紧 )

顺便说一下,MQ在实现CLinkedListNode和CRedBlackTreeNode方面还有一个错误。(除了m_value)是只由列表类本身来改变的。 其他人不需要改变它们。 这就是为什么它们在dotnet中是内部字段。MQ已经创建了公共方法来修改这些字段,至少他们会给它们一个特定的名称...但没有,只是一般的名字。

void              Next(CLinkedListNode<T>*value)     { m_next=value; }
 

大家好!

除了通过CopyTo复制项目和手动删除项目外,还有什么其他方法可以删除CHashMap中的项目吗?

 

这里还有几件事情可以让库的拙劣实现炉火纯青。 他们的CKeyValuePair类由于某种原因继承了IComparable接口(因此也继承了IEqualityComparable),要求用户类型Key也应该支持这些接口。 尽管如果我们定义自己的比较器,就没有必要在这里面。 在原来的那个KeyValuePair当然没有接口。

如果你继续探究,你会发现更奇怪的事情。

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0)
  {
//--- check equality comaprer
   if(CheckPointer(comparer)==POINTER_INVALID)
     {
      //--- use default equality comaprer    
      m_comparer=new CDefaultEqualityComparer<TKey>();
      m_delete_comparer=true;
     }
   else
     {
      //--- use specified equality comaprer
      m_comparer=comparer;
      m_delete_comparer=false;
     }
  }

也就是说,如果你不小心把一个破损的指针传入构造函数,程序不仅会继续平静地工作,而且其逻辑也会发生变化

构造函数应该是这样的。

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0),
                                                      m_comparer(comparer),
                                                      m_delete_comparer(false)
{ }

而且没有POINTER_INVALID .而对于默认的比较器,有一个不同的构造函数签名。

 
有没有一个例子说明如何正确应用 CQueue<T>模板,并将一个任意的类作为T参数?
 
已经在一个平行线上了。要求禁止。
 

你能告诉我为什么代码不能编译吗?

#include <Generic\HashMap.mqh>
void OnStart()
  {
   CHashMap<ENUM_CHART_PROPERTY_INTEGER,int> mapI;    // эта срока компилируется без ошибок
   CHashMap<ENUM_CHART_PROPERTY_DOUBLE,double> mapD;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30
   CHashMap<ENUM_CHART_PROPERTY_STRING,string> mapS;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30

  }

问题出在系统枚举中:ENUM_CHART_PROPERTY_DOUBLE、ENUM_CHART_PROPERTY_STRING,它们都有问题。如果我使用我自己的枚举作为关键类型,那么编译 会成功。