collections - MFC 容器中的 find_if 具有从 std::iterator 派生的迭代器

标签 collections stl mfc iterator c++

我有一个 working iterator对于 MFC CObList - BaseMFCIter。它适用于循环迭代,但我仍然无法使 ListIter 与 STL 算法 find_if 一起正常工作。 代码

#include < iterator >
#include "afxwin.h"
#include "afxtempl.h"
#include <iostream>
#include <algorithm>
#include <cstdlib> 
class myCObject : public CObject
{
public:
    myCObject( std::string val )
    {
        x = val;
    }
    std::string x;
};
template < typename Item, class Cont, class Key = POSITION >
class BaseMFCIter : public std::iterator < std::input_iterator_tag, Item >
{
public:
    // Define types for the 2 member functions to be used:
    typedef Key  (Cont::*GetFirstFunctionPtr) ()     const;
    typedef Item    (Cont::*GetNextFunctionPtr)  (Key&) const;


    // Default constructor, makes a null iterator, equal to BaseMFCIter::end()
    BaseMFCIter() : m_pCont(0), m_Pos(0), m_GetFirstFunc(0), m_GetNextFunc(0), m_End(true) {}

    // Constructor taking pointer to container and the iteration functions
    BaseMFCIter(Cont* pCont, GetFirstFunctionPtr pFF, GetNextFunctionPtr pNF) 
        : m_pCont(pCont), m_Pos(0), m_GetFirstFunc(pFF), m_GetNextFunc(pNF)
    { init(); }

    // Copy constructor, initialises iterator to first element
    BaseMFCIter(const BaseMFCIter& vi) : m_pCont(vi.m_pCont), m_Pos(0),
        m_GetFirstFunc(vi.m_GetFirstFunc), m_GetNextFunc(vi.m_GetNextFunc)
    { init(); }

    // Assignment operator, initialises iterator to first element
    BaseMFCIter& operator=(const BaseMFCIter& vi)
    {
        m_pCont     = vi.m_pCont; 
        m_GetFirstFunc  = vi.m_GetFirstFunc;
        m_GetNextFunc   = vi.m_GetNextFunc;
        init();  
        return *this; 
    }

    bool operator == (const BaseMFCIter& rhs) const
    { return (m_Pos == rhs.m_Pos && m_End == rhs.m_End); }

    bool operator != (const BaseMFCIter& rhs) const 
    { return !operator==(rhs); }

    BaseMFCIter&    operator ++ ()    { advance(); return *this; }
    BaseMFCIter&    operator ++ (int) { BaseMFCIter ret(*this); advance(); return ret; }
    Item            operator *  ()    { return m_Item; }
    Item            operator -> ()    { return m_Item; }

    static BaseMFCIter end   ()    { return BaseMFCIter(); }    // end() returns default null iterator

private:
    Item     m_Item;      // Current item from container
    Cont* m_pCont;     // Pointer to container
    Key  m_Pos;       // Key to item in container
    bool     m_End;       // Flag to indicate end of container reached

    // Pointers to container iteration functions
    GetFirstFunctionPtr m_GetFirstFunc;
    GetNextFunctionPtr  m_GetNextFunc;

    // Use container GetFirst & GetNext functions to set to first element, or end() if not found
    void init() 
    {
        m_Pos = 0;
        m_End = true;

        if (m_pCont && m_GetFirstFunc != 0)
        {
            m_Pos = (m_pCont->*m_GetFirstFunc)();
            advance();
        }
    }

    // Use container GetNext function to find next element in container
    void advance()
    {
        m_End = m_Pos ? false : true;
        m_Item = (m_Pos && m_pCont && m_GetNextFunc != 0) ? 
            (m_pCont->*m_GetNextFunc)(m_Pos) : Item();
    }
};
    struct Container : public CObList
    {
        myCObject*       GetNext(POSITION& rPosition)
        {
            return dynamic_cast<myCObject*>(CObList::GetNext(rPosition));
        }
        myCObject const* GetNext(POSITION& rPosition) const
        { 
            return dynamic_cast<const myCObject*>(CObList::GetNext(rPosition)); 
        }
    };


    class ListIter : public BaseMFCIter < const myCObject*, Container, POSITION  >
    {
    public:
        ListIter( Container* pObj = 0)  
            : BaseMFCIter< const myCObject*, Container, POSITION >
                (pObj, &CObList::GetHeadPosition, &Container::GetNext)
        {
        }
    };

    struct Comparator
    {
        std::string stringToCompare;
        bool operator() ( const myCObject* lhs )
        {
            return (bool) lhs->x.compare( stringToCompare );
        }
    };

    void main( )
    {


        myCObject* m = new myCObject( "one" );
        myCObject* n = new myCObject( "two" );
        myCObject* p = new myCObject( "three" );
        myCObject* q = new myCObject( "four" );

        Container cont;
        cont.AddHead( m );
        cont.AddHead( n );
        cont.AddHead( p );
        cont.AddHead( q );

        Comparator pred;
        pred.stringToCompare = "1";
        ListIter iter = ListIter( &cont );
        ListIter endIter = ListIter( );
        ListIter foundIter = std::find_if( iter, endIter, pred );

        std::cout << "foundIter x is: " << foundIter->x.c_str() << std::endl;

    }

给我 foundIter x is: four。这可能是由于结束位置的定义方式而发生的

_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
    {   // find first satisfying _Pred
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Pred);
    for (; _First != _Last; ++_First)
        if (_Pred(*_First))
            break;
    return (_First);
    }

没有正确迭代,但我不知道如何修复它。

最佳答案

修复了一些问题:

  • (bool) lhs->x.compare( stringToCompare ) 返回 true _whenever the string don't match** (see string::compare)
  • 您正在搜索不存在的“1”
  • 由于谓词错误,您收到了第一个匹配项,即第一个元素,也插入了最后一个元素,名称为 "four" :)
  • 您没有检查是否找到了有效的匹配项(取消引用结束迭代器是非法的,可能会使您的程序崩溃或做更糟糕的事情:未定义的行为)
  • 你在输出语句中有一个多余的x.c_str()
  • 我将 Compare 谓词更改为更加地道:

    • 从构造函数中初始化stringToCompare
    • 使字段const
    • 使operator()成为const方法

这应该可以解决问题(未经测试的代码,接下来的几个小时我不在编译器附近)

更新

到家后,我终于打开了调试器来跟踪那个奇怪的行为(见评论)。

令我沮丧的是,我发现 BaseMFCIter 是由对迭代器 是什么 的理解非常有限的人设计的:复制构造函数和赋值运算符完全错误:它们的效果是为同一个集合创建了一个新的 begin 迭代器。然而,这意味着迭代器永远不会从函数返回。

因此,我修复了它(首先通过正确实现它,然后通过删除现在冗余的构造函数和 operator= 以支持编译器生成的默认实现)。

查看 full history of my and your edits :

git clone git://gist.github.com/1353471.git
  • sehe 11 分钟前依赖默认生成的复制构造函数和赋值
  • sehe 12 分钟前修复了损坏的复制构造函数和赋值
  • sehe 65 分钟前暂定
  • Dmitry 73 分钟前尝试使用谓词查找 find_if
  • sehe Heeren 25 小时前修复和测试 (VS2010)
  • sehe 25 小时前 ( STL iterator for MFC container CObList )

#include "afxwin.h"
#include "afxtempl.h"
#include <iostream>
#include <algorithm>
#include <cstdlib> 
#include <string>
#include <iterator>

class myCObject : public CObject
{
public:
    myCObject( const std::string& val ) { x = val; }
    std::string x;
};

template < typename Item, class Cont, class Key = POSITION >
class BaseMFCIter : public std::iterator < std::input_iterator_tag, Item >
{
public:
    // Define types for the 2 member functions to be used:
    typedef Key  (Cont::*GetFirstFunctionPtr) ()     const;
    typedef Item    (Cont::*GetNextFunctionPtr)  (Key&) const;

    // Default constructor, makes a null iterator, equal to BaseMFCIter::end()
    BaseMFCIter() : m_pCont(0), m_Pos(0), m_GetFirstFunc(0), m_GetNextFunc(0), m_End(true) {}

    // Constructor taking pointer to container and the iteration functions
    BaseMFCIter(Cont* pCont, GetFirstFunctionPtr pFF, GetNextFunctionPtr pNF) 
        : m_pCont(pCont), m_Pos(0), m_GetFirstFunc(pFF), m_GetNextFunc(pNF)
    { init(); }

    bool operator == (const BaseMFCIter& rhs) const
    { return (m_Pos == rhs.m_Pos && m_End == rhs.m_End); }

    bool operator != (const BaseMFCIter& rhs) const 
    { return !operator==(rhs); }

    BaseMFCIter&    operator ++ ()    { advance(); return *this; }
    BaseMFCIter&    operator ++ (int) { BaseMFCIter ret(*this); advance(); return ret; }
    Item            operator *  ()    { return m_Item; }
    Item            operator -> ()    { return m_Item; }

    static BaseMFCIter end   ()    { return BaseMFCIter(); }    // end() returns default null iterator

private:
    Item  m_Item;   // Current item from container
    Cont* m_pCont;  // Pointer to container
    Key   m_Pos;    // Key to item in container
    bool  m_End;    // Flag to indicate end of container reached

    // Pointers to container iteration functions
    GetFirstFunctionPtr m_GetFirstFunc;
    GetNextFunctionPtr  m_GetNextFunc;

    // Use container GetFirst & GetNext functions to set to first element, or end() if not found
    void init() 
    {
        m_Pos = 0;
        m_End = true;

        if (m_pCont && m_GetFirstFunc != 0)
        {
            m_Pos = (m_pCont->*m_GetFirstFunc)();
            advance();
        }
    }

    // Use container GetNext function to find next element in container
    void advance()
    {
        m_End = m_Pos ? false : true;
        m_Item = (m_Pos && m_pCont && m_GetNextFunc != 0) ? 
            (m_pCont->*m_GetNextFunc)(m_Pos) : Item();
    }
};

struct Container : public CObList
{
    myCObject* GetNext(POSITION& rPosition)
    {
        return dynamic_cast<myCObject*>(CObList::GetNext(rPosition));
    }
    myCObject const* GetNext(POSITION& rPosition) const
    { 
        return dynamic_cast<const myCObject*>(CObList::GetNext(rPosition)); 
    }
};


class ListIter : public BaseMFCIter < const myCObject*, Container, POSITION  >
{
public:
    ListIter( Container* pObj = 0)  
        : BaseMFCIter< const myCObject*, Container, POSITION >
            (pObj, &CObList::GetHeadPosition, &Container::GetNext)
    {
    }
};

struct Comparator
{
    Comparator(const std::string& compareTo) : stringToCompare(compareTo) {}

    bool operator() ( const myCObject* lhs ) const
    {
        return 0 == lhs->x.compare( stringToCompare );
    }
  private:
    const std::string stringToCompare;
};

void main( )
{
    myCObject* m = new myCObject( "one" );
    myCObject* n = new myCObject( "two" );
    myCObject* p = new myCObject( "three" );
    myCObject* q = new myCObject( "four" );

    Container cont;
    cont.AddHead( m );
    cont.AddHead( n );
    cont.AddHead( p );
    cont.AddHead( q );

    Comparator pred("three");
    ListIter iter = ListIter(&cont),
             endIter = ListIter( );

    ListIter foundIter = std::find_if( iter, endIter, pred );

    if (endIter != foundIter)
    {
        std::cout << "foundIter x is: " << foundIter->x << std::endl;
    }
    else
    {
        std::cout << "not found" << std::endl;
    }
}

关于collections - MFC 容器中的 find_if 具有从 std::iterator 派生的迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8081735/

相关文章:

java - 使用集合按顺序存储待处理的对象

c++ - 与 std::vector 的元素进行组合

c++ - 多个代理类可以组成一个 STL 证明位 vector 吗?

c++ - 更改 CMFCRibbonStatusBar 的文本,但显示第一个字符和三个点(如 "C...")

visual-studio-2008 - 如何将 MFC 应用程序移植到 Windows Embedded Compact 7?

java - 如何使用 Java 8 Stream API 过滤集合中的列表

vb.net - List(of String) 或 Array 或 ArrayList

java - 如何对Arraylist的类别进行排序?

c++ - 使用 vector 迭代器不匹配 ‘operator=’

c++ - 在 MFC 上单击按钮时显示文本