Computing.Net > Forums > Programming > CPP List class sort of a structure

CPP List class sort of a structure

Reply to Message Icon

Original Message
Name: LenN (by Len Nerenburg)
Date: January 5, 2008 at 03:00:36 Pacific
Subject: CPP List class sort of a structure
OS: xpppro
CPU/Ram: core 2 duo/4 gb
Model/Manufacturer: self built
Comment:

I am trying to use the STL list class with a structure and can't figure out how to sort it.
The following simple pgm demonstrates the problem. I use MSVC and cutting and pasting it into a simple win32 console app project works fine without the sort() but compiles with errors with the sort(). I can't figure out how to tell sort what field to use.

#include <list>
#include <iostream>
#include <utility>
#include <string>
using namespace std ;

typedef struct sFname_tag
{
string fname;
char attrib;
} fnameStruct;
typedef fnameStruct *PfnameStruct;

typedef std::list<fnameStruct> LISTSTRUCT;

void main()
{

LISTSTRUCT listStruct;
LISTSTRUCT::iterator i;
fnameStruct fnameS;
PfnameStruct pfnameS = &fnameS;

// Insert 3 items one at a time
pfnameS->fname = "wolf";
pfnameS->attrib = 'W';
listStruct.insert (listStruct.begin(), fnameS);

pfnameS->fname = "bear";
pfnameS->attrib = 'B';
listStruct.insert (listStruct.begin(), fnameS);

pfnameS->fname = "aardvark";
pfnameS->attrib = 'A';
listStruct.insert (listStruct.end(), fnameS);

/* this prints out list struct members */
for (i = listStruct.begin(); i != listStruct.end(); ++i)
{
fnameS = *i;
cout << fnameS.fname << " attrib=" << fnameS.attrib << endl;
// ************************************
// here's where the problem is
cout << "--- Sorted ---" << endl;
/* comment out the listStruct.sort() and it compiles and runs fine - with this in it compiles with errors and I can't figure out how to make it understand what field to sort on - i.e. the fname field */

listStruct.sort();
// ************************************
}



Report Offensive Message For Removal


Response Number 1
Name: LenN (by Len Nerenburg)
Date: January 5, 2008 at 03:04:26 Pacific
Reply: (edit)

The print of the members is missing a } due to the cutting and pasting apparently.

should be:
for (i = listStruct.begin(); i != listStruct.end(); ++i)
{
fnameS = *i;
cout << fnameS.fname << " attrib=" << fnameS.attrib << endl;
}


Report Offensive Follow Up For Removal

Response Number 2
Name: klint
Date: January 5, 2008 at 04:48:26 Pacific
Reply: (edit)

Len,

std::list::sort() requires your contained type to have a less-than operator (<) defined. So you need to write the following just before your main function (I haven't tested this so I hope it works):

boolean operator<(
const fnameStruct& left,
const fnameStruct& right)
{
return left.fname < right.fname;
}

I hope that works.

If you like, I can offer you a few more suggestions about your code. (Most of the advice below can be fully researched in a good book like Scott Meyers' Effective C++.)



#include <utility>

What's that for? You don't seem to be using <utility>.


typedef struct sFname_tag
{
...
} fnameStruct;

You can simply do
struct fnameStruct
{
...
};

(or struct FnameStruct as it's conventional to capitalize struct and class names.)


typedef std::list<fnameStruct> LISTSTRUCT;

Most experienced C++ programmers recommend using all-capitals only for the preprocessor. So the above would conventionally be called ListStruct.


LISTSTRUCT::iterator i;

It's recommended declaring variable at the point of first use. In this case, that would be inside the parenthesis after the for statement.


for (i = listStruct.begin(); i != listStruct.end(); ++i)
{
fnameS = *i;
...
}

This performs an unnecessary copy of the whole stucture. This would have been expensive if your structure was much larger. You can avoid the copy by using a reference:

for (i = listStruct.begin(); i != listStruct.end(); ++i)
{
const FnameStruct & fnameS = *i;
...
}


listStruct.sort();

Once you've declared your less-than operator, this should work.

Finally, looking at your code again, I was wondering if a list is really what you need. Are you creating a lookup table of names and attributes? Then perhaps std::map(string, char) would be more suitable, and then you can get rid of the structure, and you won't have to worry about sorting.


Report Offensive Follow Up For Removal

Response Number 3
Name: LenN (by Len Nerenburg)
Date: January 5, 2008 at 14:10:01 Pacific
Reply: (edit)

Thx Klint, the operator< worked perfectly. I also appreciate the techniques that you mentioned. I incorporated your suggestions. The structurename_tag thing comes from the way that we do stuff at work (I work for a software company) and I just carry some of their techniques until I find something better.

The utility header is superfluous. I put it in, read of it somewhere in the MSVC doc, and thought it might have something to do with the problems that I had or a solution to it. Desperation.

Regarding whether to use Map or List (or any other container class): This was something of an exercise for me to teach myself some STL container class stuff. I'm an old mainframe software guy (26 years). My expertise is in IBM assembler, COBOL, REXX but I've worked on PCs on and off for the last 12 years at my current job - some SASC for the mainframe and some MSVC on windows also. I like MSVC. Compared to what I worked on for decades, object code debuggers etc, MSVC is like playing a video game. Very powerful and fun. You can write, test and debug code in a fraction of the time it took us to do things 20 years ago (and even today on mainframes).

I wrote my own double linked list application for a program that I wrote to read directories and report on what's in them and another to find all my music directories and create a report on what I have and playlists for each directory. So the structure that I was working with was a DOS directory structure (_finddata_t). There was no need for a double linked list... I just did it for an exercise... it was more of a challenge than working with a simple array of structures. Same reason for learning about STL LIST (or MAP or VECTOR or ARRAY - probably all would do). Learning the in's and out's of one container class translates well to the other container classes. As I write stuff for work or home I want to take advantage of what's out there instead of re-inventing the wheel. Writing my own double linked list was satisfying as an exercise but there are bigger fish to fry.

Again, thanks for your answer and suggestions.

Len


Report Offensive Follow Up For Removal

Response Number 4
Name: klint
Date: January 5, 2008 at 15:47:08 Pacific
Reply: (edit)

It's nice to hear about you. I'm experienced on a variety of systems and languages too, though not IBM mainframes. Having experience of other systems gives you valuable skills for new stuff too. And doing exercises, as you are doing, is important for learning stuff. (As the proverb goes, "I see and I understand; I do and I remember." Or something like that.)

By the way, if PCs are not the only system you work on, you should be aware that "void main()" is not standard C++ and therefore not portable to other systems. It should be "int main()".

Cheers and good luck - C++ is probably the world's most complicated language, it takes years to learn properly but it's worth it.


Report Offensive Follow Up For Removal

Response Number 5
Name: LenN (by Len Nerenburg)
Date: January 6, 2008 at 03:38:15 Pacific
Reply: (edit)

Generally I do use int main and return a return code. The 'template' for LIST was a simple LIST sample pgm (with void main), from the MSVC help/ documentation for some integers, that I extended to the more likely real world structure app. That is where the caps for LISTSTRUCT came from, it was LISTINT in caps from MSVC. At work we use caps for preprocessor as you pointed out. I made the changes that you suggested since what I wrote will be used as a skeleton (template) for future programs and it's best to develop good habits early than unlearn bad ones.

My experience with programming languages translates well to new ones since they all essentially do the same things and have the same constructs. C++ is a bit of a bear - rich in features and cryptic enough to give me fits - and this is from someone who has worked with assembly language for 26 years (even wrote some 6502 assembly for my old Commodore 64 - 6502 makes IBM assembler look like a high-level language!). Java, on the other hand, simplifies C++ by removing lots of the pointer stuff. Same for operating systems. Knowing IBM mainframe internals translates well conceptually to others (PC's, Unix etc) . They all do the same things and IBM wrote the book on it (they gave away the op sys to sell the hardware in the old days - after all, what good was the box without an opsys). They were the ones who taught Bill Gates and Microsoft how to do it right... and he screwed them royally on OS/2 - a real 32-bit non-preemptive multi-tasking opsys, which windows 3.1 wasn't, that could run windows pgms, in a win-os2 window, better than windows could... but that's another story.

Anyway, thx for your help and tips. Some old dogs can be taught new tricks!

Len


Report Offensive Follow Up For Removal







Use following form to reply to current message:

   Name: From My Computing.Net Settings
 E-Mail: From My Computing.Net Settings

Subject: CPP List class sort of a structure 

Comments:

 


  Homepage URL (*): 
Homepage Title (*): 
         Image URL: 
 
Data Recovery Software




Have you ever used OpenOffice?

Yes, as my main suite.
Yes, occationally.
Yes, but only once.
No, never.


View Results

Poll Finishes In 5 Days.
Discuss in The Lounge