Sort a Vector of Pointers to an object, based on objects properties

S

sandy

I am trying to make a simulated directory structure application for a
course.

I am using a Vector to store pointers to my Directory objects (as
subdirectories of the current object).

In my header it looks like this (private section)

vector<Directory*> Directories;

In my cpp file in the constructor I have this:

Directories.clear();

To add directories to the Vector I have a function that asks for name
of the directory and checks it for validity etc. then passes it off to
create and store the new subdirectory using this function:

bool Directory::Create(string DN) //pass in directory name
{
Directory *ND = new Directory(this, DN);
Directories.push_back(ND);
NumSubDirs++;

sort(Directories.begin(), Directories.end());

return true;
}


As you can see I am calling the sort function. As you may guess from
the fact that I am posting the sort does not work. I am 99% sure it's
because I need to come up with the correct method of overloading the <
operator and the > operator.

When sort is called the values change position, they just aren't sorted
by directory name as requested.

I have the following overloaded operator< and operator> functions. (I
am not including the headers) which do NOT do the trick.

bool Directory::eek:perator<(const Directory & D)
{
return D.Name < Name;

}

bool Directory::eek:perator<(const Directory *D)
{
return D->Name < this->Name;
}


/*
operator>
*/
bool Directory::eek:perator>(const Directory & D)
{
return Name > D.Name;
}
bool Directory::eek:perator>(const Directory * D)
{
return D->Name > Name;
}

I am sure that's the problem, I just don't know how to tell it the
correct thing to do...

Thanks.
 
V

Victor Bazarov

I am trying to make a simulated directory structure application for a
course.

I am using a Vector to store pointers to my Directory objects (as
subdirectories of the current object).

In my header it looks like this (private section)

vector<Directory*> Directories;

In my cpp file in the constructor I have this:

Directories.clear();

To add directories to the Vector I have a function that asks for name
of the directory and checks it for validity etc. then passes it off to
create and store the new subdirectory using this function:

bool Directory::Create(string DN) //pass in directory name
{
Directory *ND = new Directory(this, DN);
Directories.push_back(ND);
NumSubDirs++;

sort(Directories.begin(), Directories.end());

return true;
}


As you can see I am calling the sort function. As you may guess from
the fact that I am posting the sort does not work. I am 99% sure it's
because I need to come up with the correct method of overloading the <
operator and the > operator.

When sort is called the values change position, they just aren't
sorted by directory name as requested.

I have the following overloaded operator< and operator> functions. (I
am not including the headers) which do NOT do the trick.

bool Directory::eek:perator<(const Directory & D)
{
return D.Name < Name;

}

bool Directory::eek:perator<(const Directory *D)
{
return D->Name < this->Name;
}


/*
operator>
*/
bool Directory::eek:perator>(const Directory & D)
{
return Name > D.Name;
}
bool Directory::eek:perator>(const Directory * D)
{
return D->Name > Name;
}

I am sure that's the problem, I just don't know how to tell it the
correct thing to do...

The regular 'sort' does not compare the objects behind the pointers.
It just compares the pointers. What you need is a custom comparator
which will dereference the pointers before comparing them. Then
pass an instance of that comparator to 'sort' with 3 arguments.

RTFM about the 'sort' with 3 arguments.

BTW, what book on Standard library are you reading? Does it talk
about custom comparators?

V
 
S

Salt_Peter

I am trying to make a simulated directory structure application for a
course.

I am using a Vector to store pointers to my Directory objects (as
subdirectories of the current object).

In my header it looks like this (private section)

vector<Directory*> Directories;

In my cpp file in the constructor I have this:

Directories.clear();

To add directories to the Vector I have a function that asks for name
of the directory and checks it for validity etc. then passes it off to
create and store the new subdirectory using this function:

bool Directory::Create(string DN) //pass in directory name

Do not pass a std::string by copy. Use a const reference.
Otherwise you'll be invoking the std::string copy ctor needlessly.

bool Directory::Create( const std::string& DN )

Although that really should be in a Directory constructor.
{
Directory *ND = new Directory(this, DN);
Directories.push_back(ND);
NumSubDirs++;

sort(Directories.begin(), Directories.end());

return true;
}


As you can see I am calling the sort function. As you may guess from
the fact that I am posting the sort does not work. I am 99% sure it's
because I need to come up with the correct method of overloading the <
operator and the > operator.

When sort is called the values change position, they just aren't sorted
by directory name as requested.

I have the following overloaded operator< and operator> functions. (I
am not including the headers) which do NOT do the trick.

bool Directory::eek:perator<(const Directory & D)
{
return D.Name < Name;

}

bool Directory::eek:perator<(const Directory *D)
{
return D->Name < this->Name;
}


/*
operator>
*/
bool Directory::eek:perator>(const Directory & D)
{
return Name > D.Name;
}
bool Directory::eek:perator>(const Directory * D)
{
return D->Name > Name;
}

I am sure that's the problem, I just don't know how to tell it the
correct thing to do...

Thanks.

// Use a functor to establish comparison test - adjust as needed:

#include <algorithm>

struct DirectorySort
{
bool operator()(const Directory* const& r_left, const Directory*
const& r_right)
{
return r_left->getName() < r_right->getName();
}
};

int main()
{
std::vector< Directory* > dirs;
dirs.push_back( new Directory("dir_8") );
dirs.push_back( new Directory("dir_1") );
dirs.push_back( new Directory("dir_5") );

std::sort( dirs.begin(), dirs.end(), DirectorySort() );

// deallocate dirs ...
}
 
S

sandy

Salt_Peter said:
(e-mail address removed) wrote:

Do not pass a std::string by copy. Use a const reference.
Otherwise you'll be invoking the std::string copy ctor needlessly.

Thanks. I should go back through my code, I am sure there are other
places I did it too.
bool Directory::Create( const std::string& DN )

Although that really should be in a Directory constructor.
// Use a functor to establish comparison test - adjust as needed:

#include <algorithm>

struct DirectorySort
{
bool operator()(const Directory* const& r_left, const Directory*
const& r_right)
{
return r_left->getName() < r_right->getName();
}
};

I added this code to my header in the Private section:

struct DirectorySort
{
bool operator()(const Directory* const& r_left, const
Directory* const& r_right)
{
return r_left->getName() < r_right->getName();
}
};

I get the following compile time errors:

In member function `bool Directory::DirectorySort::eek:perator()(const
Directory* const&, const Directory* const&)':

passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

I found code similar to this on the net earlier but could never figure
out how to make it work.

Any Ideas?
 
S

sandy

Victor said:
(e-mail address removed) wrote:

RTFM about the 'sort' with 3 arguments.

BTW, what book on Standard library are you reading? Does it talk
about custom comparators?

I have two C++ books. Both make mention of vectors, the second is the
better one but neither goes into much depth (at least not enough for me
to understand).

C++ How to program - Deitel & Deitel
Data Structures and Problem Solving - Mark Allen Weiss

the second book has a fair amount but it is scattered throughout. It's
a good book, but a hard read.
 
S

sandy

Victor said:
(e-mail address removed) wrote:

RTFM about the 'sort' with 3 arguments.

BTW, what book on Standard library are you reading? Does it talk
about custom comparators?

I have two C++ books. Both make mention of vectors, the second is the
better one but neither goes into much depth (at least not enough for me
to understand).

C++ How to program - Deitel & Deitel
Data Structures and Problem Solving - Mark Allen Weiss

the second book has a fair amount but it is scattered throughout. It's
a good book, but a hard read.
 
B

BobR

(e-mail address removed) wrote in message
I added this code to my header in the Private section:

An header does not have a 'Private section'. I'm sure you meant in the class?
struct DirectorySort{
bool operator()(const Directory* const& r_left, const
Directory* const& r_right){
return r_left->getName() < r_right->getName();
}
};

I get the following compile time errors:

In member function `bool Directory::DirectorySort::eek:perator()(const
Directory* const&, const Directory* const&)':
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

I found code similar to this on the net earlier but could never figure
out how to make it work.
Any Ideas?

Yeah, but they seem to be bad ideas (non-const).
Shouldn't hurt because you are only returning a bool (nothing anybody could
use to change anything).

struct DirectorySort{
bool operator()( Directory * const r_left,
Directory * const r_right){
return r_left->GetName() < r_right->GetName();
}
};

Did you change Directory::GetName() to Directory::getName()? If so, correct
it in that struct.
 
S

sandy

BobR said:
An header does not have a 'Private section'. I'm sure you meant in the class?
Okay; Nube alert! (me)

In my class .h file in the private section is where I added it.
Yeah, but they seem to be bad ideas (non-const).
Shouldn't hurt because you are only returning a bool (nothing anybody could
use to change anything).

struct DirectorySort{
bool operator()( Directory * const r_left,
Directory * const r_right){
return r_left->GetName() < r_right->GetName();
}
};

Did you change Directory::GetName() to Directory::getName()? If so, correct
it in that struct.
I have made certain that the GetName() is case correct and tried your
code but I get the same error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers
 
B

BobR

(e-mail address removed) wrote in message ...
BobR wrote:
In my class .h file in the private section is where I added it.

I have made certain that the GetName() is case correct and tried your
code but I get the same error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers


This compiled. I don't have it fully set up yet and no data, so I don't know
if it works properly.

class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

std::string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
// File *Files; //Pointer to an array of Files
std::vector<Directory*> Directories; // vector to pointers to
directories

Directory *Parent; // pointer to this directories parent dir

struct DirectorySort{
bool operator()( Directory * const r_left,
Directory * const r_right){
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort

public:

Directory();
Directory( Directory *Parent, std::string N);

std::string GetName();

void SortDirTest();

}; //class Directory

std::string Directory::GetName(){
return Name;
}

void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() );
return;
}
 
B

BobR

Tested, good.

// --------------------------
// #includes here

class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );
// --------------------------
std::string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
// File *Files; //Pointer to an array of Files
std::vector<Directory*> Directories; // vector to pointers to
directories
Directory *Parent; // pointer to this directories parent dir

struct DirectorySort{ // note: changed back to ref. pass.
bool operator()( Directory const * const &r_left,
Directory const * const &r_right)const{
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort

// struct DirectorySort{ // - alternate (case insensitive) -
// bool operator()( Directory const * const &r_left,
// Directory const * const &r_right)const{
// std::string sL2( ToUpper(r_left->GetName()) ),
// sR2( ToUpper(r_right->GetName()) );
// return (sL2 < sR2);
// }
// std::string ToUpper(std::string S)const{
// for( size_t i(0); i < S.size(); ++i){ S[ i ] =
std::toupper(S);}
// return S;
// }
// }; // struct DirectorySort (case insensitive)
// --------------------------
public:
Directory();
Directory( Directory *Parent, std::string N);
~Directory();
// --------------------------
std::string GetName() const;
void FillVec();
void SortDirTest();
void PrintVec( std::eek:stream &out)const;
}; //class Directory
// --------------------------

/* Constructors */
Directory::Directory()
: Name(""), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(0){
//Files = new File[MaxFiles];
} //Directory() Ctor

Directory::Directory(Directory *Parent, std::string N)
: Name(N), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(Parent){
//Files = new File[MaxFiles];
} //Directory(Directory*,string) Ctor

Directory::~Directory(){
//delete[] Files;
// vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
// --------------------------
std::string Directory::GetName() const {
return Name;
}
// --------------------------
void Directory::FillVec(){
std::istringstream sis("Don't chase the rainbow"
" looking for the pot of gold, just pick up"
" the diamonds along the way.");
std::string temp;
while( sis>>temp ){
Directories.push_back( new Directory( this, temp ) );
++NumSubDirs;
} // while(sis)
return;
} // FillVec()
// --------------------------
void Directory::printVec( std::eek:stream &out)const{
for( size_t i(0); i < Directories.size(); ++i ){
out<<Directories.at( i )->GetName()<<std::endl;
}
} // PrintVec(ostream)
// --------------------------
void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() );
return;
}
// --------------------------

int main(){
using std::cout; // for NG post
cout<<"\n___ Directory dir(); ___"<<std::endl;
Directory dir;
dir.FillVec();
dir.PrintVec( cout );
cout<<"___ dir.SortDirTest(); ___"<<std::endl;
dir.SortDirTest();
dir.PrintVec( cout );
cout<<"___ Done ___"<<std::endl;
return 0;
} // main()

// - output -
___ Directory dir(); ___
Don't
chase
the
rainbow
looking
for
the
pot
of
gold,
just
pick
up
the
diamonds
along
the
way.
___ dir.SortDirTest(); ___
Don't
along
chase
diamonds
for
gold,
just
looking
of
pick
pot
rainbow
the
the
the
the
up
way.
___ Done ___
 
S

Salt_Peter

Thanks. I should go back through my code, I am sure there are other
places I did it too.



I added this code to my header in the Private section:

struct DirectorySort
{
bool operator()(const Directory* const& r_left, const
Directory* const& r_right)
{
return r_left->getName() < r_right->getName();
}
};

I get the following compile time errors:

In member function `bool Directory::DirectorySort::eek:perator()(const
Directory* const&, const Directory* const&)':

passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

I found code similar to this on the net earlier but could never figure
out how to make it work.

Any Ideas?

Its often difficult to pin down what is "the right way" and "the wrong
way" of organizing code. The requisites and requirements should dictate
what should go where exactly.
In this case i don't see why a Directory should have as a member
function, a functor that sorts the contents of a container of Directory
*pointers* (even saying it is painful). A pointer to a Directory is a
pointer, not a Directory. So that comparator should not be a member.
Member functions have a this parameter, which is useless here since you
dealing with pointers, not Directories. What you can do is provide a
member operator< for Directories to sort using their names.

As Scott Meyers wrote in Effective C++: prefer non-member functions
where functional extensibility is compromised. The comparator here is a
good example.

I'ld suggest taking that comparator and placing it in a namespace (ie:
utility). Because who knows when you'll be able to reuse again. You
loose that crucial benefit if you make the comparator a member
function. In the code below, note that the comparator is templated and
therefore can be used to compare *any* object using a shared_pointer
that has a get() member.

Next, don't use new/delete. Instead, use a shared_ptr. Why? Because the
added work pays itself back with interest. You no longer have to worry
about having to delete allocations.
Shared_ptr like boost/shred_ptr are simple to use.

#include <boost/shared_ptr.hpp>
int main()
{
boost::shared_ptr< Directory > sp_dir( new Directory("string") );
} // the allocation gets zapped here automatically

If you have a container of Directory objects - not pointers, a *member
function* operator< is enough to sort with. I've included a vector of
Directories below to illustrate sorting by op<.
Imagine the code below where the namespace utility and its templated
comparator are kept in a distinct header for reuse (part of a reuseable
universal toolset).

Note: i can forget having to delete anything since thats now done
automatically.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/shared_ptr.hpp>

class Directory {
std::string s;
public:
Directory( const std::string& r_s ) : s( r_s ) { }
~Directory() {
std::cout << "~D()\n";
}
const std::string& get() const {
return s;
}
bool operator<(const Directory& r_dir) const {
return s < r_dir.get();
}
};

namespace utility { // place this utility in a utility.hpp file

template< typename T >
struct sort_by_shared_ptr { // member function get() required

typedef typename boost::shared_ptr< T > SP_T;
bool operator() ( const SP_T& r_left, const SP_T& r_right ) {
return r_left->get() < r_right->get();
}

// why not provide a reverse_sort_by_shared_ptr ?
};

} // namespace utility

int main( ) {
// type-define a shared_ptr for Directory
typedef boost::shared_ptr< Directory > SP_Dir;
// a container of the above typedef
std::vector< SP_Dir > dirs;
dirs.push_back( SP_Dir( new Directory( "dir_8" )) );
dirs.push_back( SP_Dir( new Directory( "dir_5" )) );
dirs.push_back( SP_Dir( new Directory( "dir_1" )) );

// sort using utility's templated comparator
std::sort( dirs.begin(),
dirs.end(),
utility::sort_by_shared_ptr< Directory >() );

typedef std::vector< SP_Dir >::iterator SPDIter;
for ( SPDIter it = dirs.begin(); it != dirs.end(); ++it ) {
std::cout << ( *it )->get() << std::endl;
}

// a container of plain Directories
std::vector< Directory > sdir;
sdir.push_back( Directory("dir_8") );
sdir.push_back( Directory("dir_5") );
sdir.push_back( Directory("dir_1") );

std::sort( sdir.begin(), sdir.end() ); // uses member function op<

typedef std::vector< Directory >::iterator DIter;
for ( DIter it = sdir.begin(); it != sdir.end(); ++it ) {
std::cout << ( *it ).get() << std::endl;
}

return 0;
}

Shared_ptrs like boost::shared_ptr have other benefits that i'm not
going to detail here. They are a requirement, in my opinion, to write
better code. Its a win-win situation.
 
S

sandy

BobR said:
Tested, good.

// --------------------------
// #includes here

class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );
// --------------------------
std::string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
// File *Files; //Pointer to an array of Files
std::vector<Directory*> Directories; // vector to pointers to
directories
Directory *Parent; // pointer to this directories parent dir

struct DirectorySort{ // note: changed back to ref. pass.
bool operator()( Directory const * const &r_left,
Directory const * const &r_right)const{
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort

// struct DirectorySort{ // - alternate (case insensitive) -
// bool operator()( Directory const * const &r_left,
// Directory const * const &r_right)const{
// std::string sL2( ToUpper(r_left->GetName()) ),
// sR2( ToUpper(r_right->GetName()) );
// return (sL2 < sR2);
// }
// std::string ToUpper(std::string S)const{
// for( size_t i(0); i < S.size(); ++i){ S[ i ] =
std::toupper(S);}
// return S;
// }
// }; // struct DirectorySort (case insensitive)
// --------------------------
public:
Directory();
Directory( Directory *Parent, std::string N);
~Directory();
// --------------------------
std::string GetName() const;
void FillVec();
void SortDirTest();
void PrintVec( std::eek:stream &out)const;
}; //class Directory
// --------------------------

/* Constructors */
Directory::Directory()
: Name(""), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(0){
//Files = new File[MaxFiles];
} //Directory() Ctor

Directory::Directory(Directory *Parent, std::string N)
: Name(N), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(Parent){
//Files = new File[MaxFiles];
} //Directory(Directory*,string) Ctor

Directory::~Directory(){
//delete[] Files;
// vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
// --------------------------
std::string Directory::GetName() const {
return Name;
}
// --------------------------
void Directory::FillVec(){
std::istringstream sis("Don't chase the rainbow"
" looking for the pot of gold, just pick up"
" the diamonds along the way.");
std::string temp;
while( sis>>temp ){
Directories.push_back( new Directory( this, temp ) );
++NumSubDirs;
} // while(sis)
return;
} // FillVec()
// --------------------------
void Directory::printVec( std::eek:stream &out)const{
for( size_t i(0); i < Directories.size(); ++i ){
out<<Directories.at( i )->GetName()<<std::endl;
}
} // PrintVec(ostream)
// --------------------------
void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() );
return;
}
// --------------------------

int main(){
using std::cout; // for NG post
cout<<"\n___ Directory dir(); ___"<<std::endl;
Directory dir;
dir.FillVec();
dir.PrintVec( cout );
cout<<"___ dir.SortDirTest(); ___"<<std::endl;
dir.SortDirTest();
dir.PrintVec( cout );
cout<<"___ Done ___"<<std::endl;
return 0;
} // main()

// - output -
___ Directory dir(); ___
Don't
chase
the
rainbow
looking
for
the
pot
of
gold,
just
pick
up
the
diamonds
along
the
way.
___ dir.SortDirTest(); ___
Don't
along
chase
diamonds
for
gold,
just
looking
of
pick
pot
rainbow
the
the
the
the
up
way.
___ Done ___


Bob;

Thanks for all that. I STILL can't get it to compile. I am using
DEV-C++. I am not allowed to use any extra classes /headers like boost
etc. so I don't.

When I try to compile I still get (for this line:)
return (r_left->GetName() < r_right->GetName())

error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

The course I am taking doesn't really introduce your dev environment,
you are just supposed to figure it out on your own. Is it possible I
need to change something (somewhere... somehow) to do with my compile
options??

I've had a number of suggestions like this one (and come up with a few
of my own) but they all seem to come up with the sam kind of error.
 
S

sandy

Salt_Peter said:
Its often difficult to pin down what is "the right way" and "the wrong
way" of organizing code. The requisites and requirements should dictate
what should go where exactly.
In this case i don't see why a Directory should have as a member
function, a functor that sorts the contents of a container of Directory
*pointers* (even saying it is painful). A pointer to a Directory is a
pointer, not a Directory. So that comparator should not be a member.
Member functions have a this parameter, which is useless here since you
dealing with pointers, not Directories. What you can do is provide a
member operator< for Directories to sort using their names.

As Scott Meyers wrote in Effective C++: prefer non-member functions
where functional extensibility is compromised. The comparator here is a
good example.

I'ld suggest taking that comparator and placing it in a namespace (ie:
utility). Because who knows when you'll be able to reuse again. You
loose that crucial benefit if you make the comparator a member
function. In the code below, note that the comparator is templated and
therefore can be used to compare *any* object using a shared_pointer
that has a get() member.

Next, don't use new/delete. Instead, use a shared_ptr. Why? Because the
added work pays itself back with interest. You no longer have to worry
about having to delete allocations.
Shared_ptr like boost/shred_ptr are simple to use.

#include <boost/shared_ptr.hpp>
int main()
{
boost::shared_ptr< Directory > sp_dir( new Directory("string") );
} // the allocation gets zapped here automatically

If you have a container of Directory objects - not pointers, a *member
function* operator< is enough to sort with. I've included a vector of
Directories below to illustrate sorting by op<.
Imagine the code below where the namespace utility and its templated
comparator are kept in a distinct header for reuse (part of a reuseable
universal toolset).

Note: i can forget having to delete anything since thats now done
automatically.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/shared_ptr.hpp>

class Directory {
std::string s;
public:
Directory( const std::string& r_s ) : s( r_s ) { }
~Directory() {
std::cout << "~D()\n";
}
const std::string& get() const {
return s;
}
bool operator<(const Directory& r_dir) const {
return s < r_dir.get();
}
};

namespace utility { // place this utility in a utility.hpp file

template< typename T >
struct sort_by_shared_ptr { // member function get() required

typedef typename boost::shared_ptr< T > SP_T;
bool operator() ( const SP_T& r_left, const SP_T& r_right ) {
return r_left->get() < r_right->get();
}

// why not provide a reverse_sort_by_shared_ptr ?
};

} // namespace utility

int main( ) {
// type-define a shared_ptr for Directory
typedef boost::shared_ptr< Directory > SP_Dir;
// a container of the above typedef
std::vector< SP_Dir > dirs;
dirs.push_back( SP_Dir( new Directory( "dir_8" )) );
dirs.push_back( SP_Dir( new Directory( "dir_5" )) );
dirs.push_back( SP_Dir( new Directory( "dir_1" )) );

// sort using utility's templated comparator
std::sort( dirs.begin(),
dirs.end(),
utility::sort_by_shared_ptr< Directory >() );

typedef std::vector< SP_Dir >::iterator SPDIter;
for ( SPDIter it = dirs.begin(); it != dirs.end(); ++it ) {
std::cout << ( *it )->get() << std::endl;
}

// a container of plain Directories
std::vector< Directory > sdir;
sdir.push_back( Directory("dir_8") );
sdir.push_back( Directory("dir_5") );
sdir.push_back( Directory("dir_1") );

std::sort( sdir.begin(), sdir.end() ); // uses member function op<

typedef std::vector< Directory >::iterator DIter;
for ( DIter it = sdir.begin(); it != sdir.end(); ++it ) {
std::cout << ( *it ).get() << std::endl;
}

return 0;
}

Shared_ptrs like boost::shared_ptr have other benefits that i'm not
going to detail here. They are a requirement, in my opinion, to write
better code. Its a win-win situation.

Thanks. Unfortunately (I probably should have mentioned it) for this
assignment we are not allowed to use outside classes/templates etc. so
I can't use boost.

I have seen it mentioned in a lot of postings, even the teaching
assistant talks highly of it. I've never used it because (at least for
now... don't know about later) it's off limits.

Thanks again. I will look at the code to see what I can gleen from it
even without boost.

FYI: Currently my assignment works completely except of course my
search for directories requires I read every one in the vector for a
match because I can't sort it.

I haven't given up, but it is at a state where I can at least in good
conscience say it works. It's due first thing on the 4'th Dec 06 so I
may not get this working.
 
B

BobR

(e-mail address removed) wrote in message ...
Tested, good.
// --------------------------
[snip code, see prior post]

Bob;

Thanks for all that. I STILL can't get it to compile. I am using
DEV-C++. I am not allowed to use any extra classes /headers like boost
etc. so I don't.

I am using Dev-C++ v4.9.9.1 MinGW(GCC v3.3.1) (and wxWidgets for my TestBench
prog).
Project-->Project options-->Parameters-->C++: (wxWidgets flags removed)
-fexceptions
-Wall
# -W
#-pedantic

The '#' comments-out the options(when the 'makefile' is built), sometimes
used.
When I try to compile I still get (for this line:)
return (r_left->GetName() < r_right->GetName())

error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

** Double check that you have 'const' on 'GetName(): **

class Directory{
private:
// ..........
// --------------------------
std::string Name; // Name of the Directory
// ..........
// --------------------------
struct DirectorySort{ // note: changed back to ref. pass.
bool operator()( Directory const * const &r_left,
Directory const * const &r_right)const{
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort
// --------------------------
public:
// ..........
// --------------------------
std::string GetName() const; // <<------- const <<------
// ..........
}; //class Directory
// --------------------------
// ..........
// --------------------------
std::string Directory::GetName() const { // <<------- const
return Name;
}
// --------------------------
// --------------------------
void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() ); // <<------ be sure you put the '()'
return;
}
// --------------------------

That was causing the problem with the code Salt_Peter showed.
Note that even though I put the 'const' different, it's *exactly* the same
thing.
(const 'binds' to the thing to it's left (default). If nothing to left, first
thing on right. So:
const int z(9); // human thinking,
int const z(9); // compiler thinking, Both same.
)
The course I am taking doesn't really introduce your dev environment,
you are just supposed to figure it out on your own. Is it possible I
need to change something (somewhere... somehow) to do with my compile
options??

I've had a number of suggestions like this one (and come up with a few
of my own) but they all seem to come up with the sam kind of error.

Check that 'const', and come back here. If it's still not compiling, show the
member function definition that uses the std::sort().

(just in case) I noticed you had overloaded some operators in class
Directory. If it's still not compiling, try temporarily commenting those out
(unlikely it's problem, but, let's be sure).
 
B

BobR

BobR wrote in message ...
(const 'binds' to the thing to it's left (default). If nothing to left, first
thing on right. So:
const int z(9); // human thinking,
int const z(9); // compiler thinking, Both same.
)

int I(9);
const int *Iptr(&I);
int const *Iptr2(&I); // int is const, pointer not.

// see where the second 'const' is in the next line?
// If the 'const' defaulted to "bind to right", this line would compile.

// const int const *Iptr3(&I); // duplicate `const'

int const * const Iptr4(&I);
// int const const *Iptr5(&I); // duplicate `const'


Also:

class Directory{
public:
// --------------------------
std::string GetName() const; // <<------- const <<------

// by putting the 'const' there, you are making a promise that the
// function will not change *anything* in the class. 'Directory' is
// being passed as const, and the compiler sees that
// (without the const) 'GetName()' might try to change something
// inside the class object. So, the compiler says, "error:".

}; //class Directory


Just wanted to 'splain a little.
 
S

sandy

BobR said:
BobR wrote in message ...

int I(9);
const int *Iptr(&I);
int const *Iptr2(&I); // int is const, pointer not.

// see where the second 'const' is in the next line?
// If the 'const' defaulted to "bind to right", this line would compile.

// const int const *Iptr3(&I); // duplicate `const'

int const * const Iptr4(&I);
// int const const *Iptr5(&I); // duplicate `const'


Also:

class Directory{
public:
// --------------------------
std::string GetName() const; // <<------- const <<------

// by putting the 'const' there, you are making a promise that the
// function will not change *anything* in the class. 'Directory' is
// being passed as const, and the compiler sees that
// (without the const) 'GetName()' might try to change something
// inside the class object. So, the compiler says, "error:".

}; //class Directory


Just wanted to 'splain a little.

Hurray!! And there was much rejoicing!!!

That was it! I needed that const!

OY! That was painful.

Thank you all for your patience!
 
S

Salt_Peter

BobR said:
Tested, good.

// --------------------------
// #includes here

class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );
// --------------------------
std::string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
// File *Files; //Pointer to an array of Files
std::vector<Directory*> Directories; // vector to pointers to
directories
Directory *Parent; // pointer to this directories parent dir

struct DirectorySort{ // note: changed back to ref. pass.
bool operator()( Directory const * const &r_left,
Directory const * const &r_right)const{
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort

// struct DirectorySort{ // - alternate (case insensitive) -
// bool operator()( Directory const * const &r_left,
// Directory const * const &r_right)const{
// std::string sL2( ToUpper(r_left->GetName()) ),
// sR2( ToUpper(r_right->GetName()) );
// return (sL2 < sR2);
// }
// std::string ToUpper(std::string S)const{
// for( size_t i(0); i < S.size(); ++i){ S[ i ] =
std::toupper(S);}
// return S;
// }
// }; // struct DirectorySort (case insensitive)
// --------------------------
public:
Directory();
Directory( Directory *Parent, std::string N);
~Directory();
// --------------------------
std::string GetName() const;
void FillVec();
void SortDirTest();
void PrintVec( std::eek:stream &out)const;
}; //class Directory
// --------------------------

/* Constructors */
Directory::Directory()
: Name(""), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(0){
//Files = new File[MaxFiles];
} //Directory() Ctor

Directory::Directory(Directory *Parent, std::string N)
: Name(N), NumSubDirs(0),
NumFiles(0), MaxSubDirs(5),
MaxFiles(5), Level(-1), Parent(Parent){
//Files = new File[MaxFiles];
} //Directory(Directory*,string) Ctor

Directory::~Directory(){
//delete[] Files;
// vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
// --------------------------
std::string Directory::GetName() const {
return Name;
}
// --------------------------
void Directory::FillVec(){
std::istringstream sis("Don't chase the rainbow"
" looking for the pot of gold, just pick up"
" the diamonds along the way.");
std::string temp;
while( sis>>temp ){
Directories.push_back( new Directory( this, temp ) );
++NumSubDirs;
} // while(sis)
return;
} // FillVec()
// --------------------------
void Directory::printVec( std::eek:stream &out)const{
for( size_t i(0); i < Directories.size(); ++i ){
out<<Directories.at( i )->GetName()<<std::endl;
}
} // PrintVec(ostream)
// --------------------------
void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() );
return;
}
// --------------------------

int main(){
using std::cout; // for NG post
cout<<"\n___ Directory dir(); ___"<<std::endl;
Directory dir;
dir.FillVec();
dir.PrintVec( cout );
cout<<"___ dir.SortDirTest(); ___"<<std::endl;
dir.SortDirTest();
dir.PrintVec( cout );
cout<<"___ Done ___"<<std::endl;
return 0;
} // main()

// - output -
___ Directory dir(); ___
Don't
chase
the
rainbow
looking
for
the
pot
of
gold,
just
pick
up
the
diamonds
along
the
way.
___ dir.SortDirTest(); ___
Don't
along
chase
diamonds
for
gold,
just
looking
of
pick
pot
rainbow
the
the
the
the
up
way.
___ Done ___


Bob;

Thanks for all that. I STILL can't get it to compile. I am using
DEV-C++. I am not allowed to use any extra classes /headers like boost
etc. so I don't.

When I try to compile I still get (for this line:)
return (r_left->GetName() < r_right->GetName())

error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers


The compiler is telling you that GetName() is discarding a constant
qualifier.
Note that my get() member function is const:
class Directory {
...
public:
...
std::string get() const; // <- const member function, no *this*
};

The function that processes the comparaison and returns
(r_left->GetName() < r_right->GetName()) is a function whith const ptrs
to const Directories. That means that the compiler must absolute
enforce that get() or GetName() does_not_modify_the_object that holds
the std::string. The function must be const is shown above.
 
S

Salt_Peter

BobR said:
(e-mail address removed) wrote in message ...
Tested, good.
// --------------------------
[snip code, see prior post]

Bob;

Thanks for all that. I STILL can't get it to compile. I am using
DEV-C++. I am not allowed to use any extra classes /headers like boost
etc. so I don't.

I am using Dev-C++ v4.9.9.1 MinGW(GCC v3.3.1) (and wxWidgets for my TestBench
prog).
Project-->Project options-->Parameters-->C++: (wxWidgets flags removed)
-fexceptions
-Wall
# -W
#-pedantic

The '#' comments-out the options(when the 'makefile' is built), sometimes
used.
When I try to compile I still get (for this line:)
return (r_left->GetName() < r_right->GetName())

error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

** Double check that you have 'const' on 'GetName(): **

class Directory{
private:
// ..........
// --------------------------
std::string Name; // Name of the Directory
// ..........
// --------------------------
struct DirectorySort{ // note: changed back to ref. pass.
bool operator()( Directory const * const &r_left,
Directory const * const &r_right)const{
return (r_left->GetName() < r_right->GetName());
}
}; // struct DirectorySort
// --------------------------
public:
// ..........
// --------------------------
std::string GetName() const; // <<------- const <<------
// ..........
}; //class Directory
// --------------------------
// ..........
// --------------------------
std::string Directory::GetName() const { // <<------- const
return Name;
}
// --------------------------
// --------------------------
void Directory::SortDirTest(){
std::sort( Directories.begin(), Directories.end(),
DirectorySort() ); // <<------ be sure you put the '()'
return;
}
// --------------------------

That was causing the problem with the code Salt_Peter showed.

For the record, the accessor i provided is and was constant.
std::string get() const;
 
S

sandy

For the record, the accessor i provided is and was constant.
std::string get() const;

sorry; I must have missed that. Although I am learning; there is a LOT
to learn and I miss things in syntax.

Thanks again for all your amazing efforts.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top