locked
Maps and Lists in C++ RRS feed

  • Question

  • Hi

    I know how I cam use the "map" template class to create a custom map of two objects. Up until now I have been OK with it. I can build the map, find entries in the map and iterate the map.

    But is there also a template list?

    I would like something like this in MFC:

    List<STRUCTUREA>

    Map<CString,STRUCTUREA list>

    So it will be a one to multiple relationship.

    Now, I know I can use CPtrArray and dynamically build a array of STRUCTUREA pointers, which I then have to delete myself. But is there a template class one can use for custom lists objects?

    VS2015

    MFC

    Thank you in advance. :)

    Andrew

    Monday, March 7, 2016 11:13 AM

Answers

  • Thank you. I will give these a try and provide feedback.

    Looks like I have to use CAtlList because I think CList is designed to use CObject derived entries?

    Am I wrong?


    Why not use std::list? Much better designed than the MFC collection classes, and portable.

    David Wilkinson | Visual C++ MVP

    • Marked as answer by Chuckie72 Monday, March 7, 2016 8:37 PM
    Monday, March 7, 2016 1:23 PM
  • I'm not an expert on the standard c++ library container classes but I don't think you need

      m_mapStudentStudyPointHistory[strStudent] = StudyPointList(); 

    The following will create an entry in the map along with it's list

    m_mapStudentStudyPointHistory[strStudent].push_back(sStudyPoint);

    And this also worked to add an entry into the map -

    m_mapStudentStudyPointHistory[strStudent1].push_back({i, COleDateTime::GetTickCount() });

    • Marked as answer by Chuckie72 Tuesday, March 8, 2016 9:22 AM
    Monday, March 7, 2016 10:56 PM

All replies

  • Monday, March 7, 2016 12:33 PM
  • Thank you. I will give these a try and provide feedback.

    Looks like I have to use CAtlList because I think CList is designed to use CObject derived entries?

    Am I wrong?

    Monday, March 7, 2016 12:47 PM
  • Thank you. I will give these a try and provide feedback.

    Looks like I have to use CAtlList because I think CList is designed to use CObject derived entries?

    Am I wrong?


    Why not use std::list? Much better designed than the MFC collection classes, and portable.

    David Wilkinson | Visual C++ MVP

    • Marked as answer by Chuckie72 Monday, March 7, 2016 8:37 PM
    Monday, March 7, 2016 1:23 PM
  • You're right about CList and CObject.

    The Standard C++ library includes the list class

    ATL also supports a variety of collection classes, including maps.  See ATL Collection CLasses

    Monday, March 7, 2016 1:26 PM
  • You're right about CList and CObject.

    The Standard C++ library includes the list class

    ATL also supports a variety of collection classes, including maps.  See ATL Collection CLasses

    Actually, CList does not require the contained type to be derived from CObject. In fact, it cannot be derived from CObject unless you define your own copy constructor and assignment operator, because CObject itself is not copyable (this same restriction holds for std::list).

    Perhaps yore thinking of CObList, which can store CObject pointers.

    There is really no need for all these specialized MFC List classes; std::list can do it all.

    If you want to store pointers in a container, you should consider using std::shared_ptr, which will automatically delete the underlying pointer when it is not being used any more.


    David Wilkinson | Visual C++ MVP

    Monday, March 7, 2016 3:26 PM
  • You're right about CList and CObject.

    The Standard C++ library includes the list class

    ATL also supports a variety of collection classes, including maps.  See ATL Collection CLasses

    Actually, CList does not require the contained type to be derived from CObject. In fact, it cannot be derived from CObject unless you define your own copy constructor and assignment operator, because CObject itself is not copyable (this same restriction holds for std::list).

    Perhaps yore thinking of CObList, which can store CObject pointers.

    There is really no need for all these specialized MFC List classes; std::list can do it all.

    If you want to store pointers in a container, you should consider using std::shared_ptr, which will automatically delete the underlying pointer when it is not being used any more.


    David Wilkinson | Visual C++ MVP

    I did refer to std::list, but thanks for pointing out my mix-up regarding CList && CObList.

    As far as the ATL/MFC collection classes go, sometimes its convenient to use them if they fit in better with other parts of your code that uses the framework.



    Monday, March 7, 2016 4:04 PM
  • Thanks guys. I think I have this working but I just want to be sure I have grasped it correctly.

    This is my definitions:

    using std::map;
    using std::list;
    
    typedef struct tagStudyPoint
    {
    	int iStudyPoint;
    	COleDateTime datMeeting;
    } S_STUDY_POINT;
    
    typedef list<S_STUDY_POINT> StudyPointList;
    typedef map<CString, StudyPointList> StudentStudyPoints;

    This is my variable declaration:

    StudentStudyPoints m_mapStudentStudyPointHistory;

    This is how I populate the map and lists:

    StudentStudyPoints::const_iterator iterStudentHistory = m_mapStudentStudyPointHistory.find(strStudent);
    if (iterStudentHistory == m_mapStudentStudyPointHistory.end()) // Doesn't yet exist
        m_mapStudentStudyPointHistory[strStudent] = StudyPointList(); // Now it does
    					
    S_STUDY_POINT sStudyPoint;
    sStudyPoint.datMeeting = datAssign;
    sStudyPoint.iStudyPoint = iLastCounsel;
    m_mapStudentStudyPointHistory[strStudent].push_back(sStudyPoint);

    Can I pass a S_STUDY_POINT directly in the push_back call somehow instead of declaring a variable?

    And this is how I use the map/list:

    // Locate the history data for the student
    CString strStudent = m_Grid.GetItemText(pItem->iRow, kColumnStudent);
    for (StudyPointList::const_iterator iterStudyPoints = m_mapStudentStudyPointHistory[strStudent].begin();
    				iterStudyPoints != m_mapStudentStudyPointHistory[strStudent].end();
    				++iterStudyPoints)
    {
    	dlgNextStudyPoint.AddStudyPointToHistory(iterStudyPoints->iStudyPoint, iterStudyPoints->datMeeting);
    }
    

    Thanks.

    Andrew


    • Edited by Chuckie72 Monday, March 7, 2016 4:50 PM
    Monday, March 7, 2016 4:48 PM
  • I'm not an expert on the standard c++ library container classes but I don't think you need

      m_mapStudentStudyPointHistory[strStudent] = StudyPointList(); 

    The following will create an entry in the map along with it's list

    m_mapStudentStudyPointHistory[strStudent].push_back(sStudyPoint);

    And this also worked to add an entry into the map -

    m_mapStudentStudyPointHistory[strStudent1].push_back({i, COleDateTime::GetTickCount() });

    • Marked as answer by Chuckie72 Tuesday, March 8, 2016 9:22 AM
    Monday, March 7, 2016 10:56 PM
  • Wish I knew that before ... :)

    Thank you!

    Tuesday, March 8, 2016 9:23 AM