Search code examples
c++sortingc++11vectorshared-ptr

Sorting Vectors Of Shared Pointers in C++


Let's say we have a simple class as such:

class Data {
private:
   std::string m_name;
   unsigned m_id;

   Data( const std::string& name, unsigned id ) :
   m_name( name ), m_id( id ) {}

   void setName( const std::string& name ) { m_name = name; }
   void setId( unsigned id ) { m_id = id; }

   std::string getName() const { return m_name; }
   unsigned    getId() const { return m_id; }
}; // Data

Now Let's say we have another class that populates and manages these in a container of smart pointer that are read in from a file.

Database.h

#ifndef DATABASE_H
#define DATABASE_H

class Data; 

class Database {
private:
    std::string m_filename;
    std::vector<std::shared_ptr<Data>> m_vpData;

public:
    explicit Database( const std::string& filename );        

    void displayByOption( unsigned option = 0 );

private:
    void parseFile();
    void display() const;

    // Sorting Methods Used for std::sort
    bool sortByName( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 );
    bool sortById( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 );

}; // Database

#endif // DATABASE_H

I'm not having any issues with the opening, reading and parsing of the file data. What I am struggling with is the methods to be passed into std::sort. These are the display methods within Database.cpp that would be of concern.

Note: I do have <algorithm> & <functional> included in my standard header along with the other appropriate stl headers.

Database.cpp

// -------------------------------------------------------------------------
// display() - Shouldn't be an issue, but here for reference
void Database::display() const {
    for ( unsigned u = 0; u < m_vpData.size(); u++ ) {
        std::cout << m_vpData[u]->getName() << "/t"
                  << m_vpData[u]->getId() << "/t" << std::endl;
     } 
} // display

// -------------------------------------------------------------------------
// displayByOption() - This function itself isn't an issue
// But the std::sort method is generating a compiler error
void Database::displayByOption( unsigned option ) {
    switch( option ) {
        case 1: { // Sort By Name
             std::sort( m_vpData.begin(), m_vpData.end(), sortByName );
             display();
             break;
         }
         case 2: { // Sort By Id
             std::sort( m_vpData.being(), m_vpData.end(), sortById );
             display();
             break;
         } 
         default : { // Unsorted - Order Read In By File
             display();
         }
     }
} // displayByOption

// -------------------------------------------------------------------------
// sortByName()
bool Database::sortByName( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 ) {
     return d1->getName() < d2->getName();
 } // sortByName

 // ------------------------------------------------------------------------
 // sortById()
 bool Database::sortById( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 ) {
     return d1->getId() < d2->getId();
 } // sortById

Here is the Compiler Error that was generated

1>------ Build started: Project: FileParse, Configuration: Debug Win32 ------
1>  CharacterDatabase.cpp
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(66): error C3867: 'CharacterDatabase::sortByName': non-standard syntax; use '&' to create a pointer to member
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(66): error C2672: 'std::sort': no matching overloaded function found
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(66): error C2780: 'void std::sort(_RanIt,_RanIt)': expects 2 arguments - 3 provided
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(3209): note: see declaration of 'std::sort'
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(71): error C3867: 'CharacterDatabase::sortByHealth': non-standard syntax; use '&' to create a pointer to member
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(71): error C2672: 'std::sort': no matching overloaded function found
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(71): error C2780: 'void std::sort(_RanIt,_RanIt)': expects 2 arguments - 3 provided
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(3209): note: see declaration of 'std::sort'
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(76): error C3867: 'CharacterDatabase::sortByExperience': non-standard syntax; use '&' to create a pointer to member
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(76): error C2672: 'std::sort': no matching overloaded function found
1>c:\users\skilz80\documents\visual studio 2015\projects\fileparse\fileparse\characterdatabase.cpp(76): error C2780: 'void std::sort(_RanIt,_RanIt)': expects 2 arguments - 3 provided
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(3209): note: see declaration of 'std::sort'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I'm usually decent in figuring out compiler errors but this one has me stumped. I've done basic sorting methods like this with basic class types that are directly stored into the container, but this is my first time trying to do it where a shared pointer of that object is stored in the vector.

What I'm not sure about is a few things.

  • Is it valid to have these sort methods to be passed into std::sort within a class? - I do not see why this should be a problem.
  • Do I need to have the parameters for the sort function to be passed to std::sort as the objects themselves or the smart pointer of them? It would make sense to pass the smart pointer since this is what is stored in the vector since we are working with the iterators begin() and end().

Any thoughts would be extremely helpful!

What is causing this file to not compile and to generate the error messages provided? The only difference is the class name between what I have posted and what I have in my editor. Also, what would be the simplest and most effective way to sort a vector<shared_ptr<Object>> that is a member of a class object?


Solution

  • The issue is that you cannot simply pass non-static member functions as part of the std::sort predicate.

    The simplest solution, given your code now, is to make Database::sortyByName and Database::sortById static member functions.

    static bool sortByName( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 );
    
    static bool sortById( const std::shared_ptr<Data>& d1, const std::shared_ptr<Data>& d2 );
    

    Note that there are various other solutions, such as using boost::bind, function objects / functors, and with C++11, lambdas. I won't go over them, but just to give you other options.