469,926 Members | 1,767 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,926 developers. It's quick & easy.

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

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 operatorfunctions. (I
am not including the headers) which do NOT do the trick.

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

}

bool Directory::operator<(const Directory *D)
{
return D->Name < this->Name;
}
/*
operator>
*/
bool Directory::operator>(const Directory & D)
{
return Name D.Name;
}
bool Directory::operator>(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.

Dec 1 '06 #1
22 2907
sa***@murdocks.on.ca wrote:
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 operatorfunctions. (I
am not including the headers) which do NOT do the trick.

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

}

bool Directory::operator<(const Directory *D)
{
return D->Name < this->Name;
}
/*
operator>
*/
bool Directory::operator>(const Directory & D)
{
return Name D.Name;
}
bool Directory::operator>(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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 1 '06 #2

sa***@murdocks.on.ca wrote:
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 operatorfunctions. (I
am not including the headers) which do NOT do the trick.

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

}

bool Directory::operator<(const Directory *D)
{
return D->Name < this->Name;
}
/*
operator>
*/
bool Directory::operator>(const Directory & D)
{
return Name D.Name;
}
bool Directory::operator>(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 ...
}

Dec 1 '06 #3

Salt_Peter wrote:
sa***@murdocks.on.ca 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::operator()(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?

Dec 1 '06 #4

Victor Bazarov wrote:
sa***@murdocks.on.ca 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.
>
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 1 '06 #5

Victor Bazarov wrote:
sa***@murdocks.on.ca 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.
>
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 1 '06 #6

sa***@murdocks.on.ca wrote in message
<11*********************@79g2000cws.googlegroups.c om>...
>
Salt_Peter wrote:
>>
// 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:
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::operator()(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.

--
Bob R
POVrookie
Dec 1 '06 #7

BobR wrote:

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?
Okay; Nube alert! (me)

In my class .h file in the private section is where I added it.

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::operator()(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.
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
--
Bob R
POVrookie
Dec 1 '06 #8

sa***@murdocks.on.ca wrote in message ...
>
BobR wrote:
In my class .h file in the private section is where I added it.
>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.
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;
}

--
Bob R
POVrookie
Dec 2 '06 #9


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[i]);}
// 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::ostream &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::ostream &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 R
POVrookie
Dec 2 '06 #10
sa***@murdocks.on.ca wrote:
Salt_Peter wrote:
sa***@murdocks.on.ca 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::operator()(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.

Dec 2 '06 #11

BobR wrote:
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[i]);}
// 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::ostream &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::ostream &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 R
POVrookie
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.

Dec 3 '06 #12

Salt_Peter wrote:
sa***@murdocks.on.ca wrote:
Salt_Peter wrote:
sa***@murdocks.on.ca 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::operator()(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.
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.

Dec 3 '06 #13

sa***@murdocks.on.ca wrote in message ...
>
BobR wrote:
>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).

--
Bob R
POVrookie
Dec 3 '06 #14

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.
--
Bob R
POVrookie
Dec 3 '06 #15

BobR wrote:
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.
--
Bob R
POVrookie
Hurray!! And there was much rejoicing!!!

That was it! I needed that const!

OY! That was painful.

Thank you all for your patience!

Dec 3 '06 #16

sa***@murdocks.on.ca wrote:
BobR wrote:
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[i]);}
// 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::ostream &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::ostream &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 R
POVrookie

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.
>
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.
Dec 3 '06 #17

BobR wrote:
sa***@murdocks.on.ca wrote in message ...

BobR wrote:
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;
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).

--
Bob R
POVrookie
Dec 3 '06 #18

Salt_Peter wrote:
>
For the record, the accessor i provided is and was constant.
std::string get() const;
Dec 4 '06 #19
>
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.

Dec 4 '06 #20

Salt_Peter wrote in message ...
>
BobR wrote:
>** Double check that you have 'const' on 'GetName(): **
// --------------------------
std::string Directory::GetName() const { // <<------- const
return Name;
}
// --------------------------
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;
In your boost example you did. In your first post (the progression I was
following), it was unspecified (but, worked fine once the const is applied.).

--
Bob R
POVrookie
Dec 4 '06 #21

sa***@murdocks.on.ca wrote:

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.
You welcome. my pleasure.

Missing the const is ok - don't worry about that.
Whats important is to understand what the compiler is telling you.
Since the Directory parameter passed to the comparator function is a
constant pointer to a constant Directory, the GetName() member function
needs to be const because otherwise the compiler wouldn't be able to
*guarentee* that the Directory parameter(s) will *not* be modified by
GetName().

const == immutable (even by accident)

That compiler is actually quite smart. Its enforcing rules depending on
how you construct the class.

Dec 4 '06 #22

sa***@murdocks.on.ca wrote in message ...
>
Hurray!! And there was much rejoicing!!!

That was it! I needed that const!

OY! That was painful.
Sometimes 'painful' forces memory. Think you'll ever forget 'const' again?
>
Thank you all for your patience!

After all that, I hope you got a decent grade!

--
Bob R
POVrookie
Dec 4 '06 #23

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Mike | last post: by
4 posts views Thread by SB | last post: by
6 posts views Thread by Der Andere | last post: by
4 posts views Thread by Johan | last post: by
3 posts views Thread by Alan | last post: by
21 posts views Thread by yeti349 | last post: by
13 posts views Thread by smp | last post: by
11 posts views Thread by Jeff Schwab | last post: by
10 posts views Thread by oktayarslan | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.