0

i have an object - Employee, and i want to know how to insert this object to a map structure sorted by char* lastName field. Thanx. My map need to contain pointers to Employee objects not the objects themselves. the key is the last name of the employee, the map need to be sorted by the employees last name, should i use multimap?

4
  • 1
    You could insert it by using std::map::insert function. Commented Sep 2, 2010 at 13:53
  • 5
    consider using std::string instead of char * to hold character strings. Commented Sep 2, 2010 at 13:55
  • From your comments it sounds like you are required to use a char *. Are you also required to use a map or can you use a set? Commented Sep 2, 2010 at 14:22
  • i can use any data structure i want, i need to hold a pointer to the employees from 2 different places. one with all the employees and other only employees from a certain department. Commented Sep 2, 2010 at 14:35

5 Answers 5

2

So you've got an std::map with a custom comparator function (you've overloaded the less than operator) and you want to insert objects so that they're in the right order?

myMap.insert( make_pair( myKey, myEmployee ) ); 

where myKey is the key to your map. However, from the sound of your question it actually sounds like you're using the object as it's own key. In that case, just use std::set and

mySet.insert( myEmployee ); 

I'd also suggest that you not use char* as a means to store lastName and prefer the std::string.

EDIT:

Following the comments down below, are you having to be able to pass in a const char* into another function? If so, still use string as it has a nice method .c_str() specifically for legacy compatibility. It can be used as so:

void stuffHappens(const char* _input){ //magic happens in here } stuffHappens( myString.c_str() ); 

and voila, you're much safer!

Sign up to request clarification or add additional context in comments.

3 Comments

Thanx for the quick reply, the first one was the one i need, the key is the last name of the employee. sure i would have used the string, unfortunately it's not allowed in my work.
@Roy, you should have mentioned this is a homework question. Please tag the question as homework.
@Roy also consider replacing your professor with a better one. There is no excuse for enforcing use of char* instead of std::string in a C++ class.
1

Define bool operator <(const Employee& other) for the Employee class. Alternatively, define bool operator <(const Employee& left, const Employee& right) as a non-member function, and make it a friend of Employee. The advantage of the first approach is that it's local to Employee, and that enhances encapsulation. The advantage of the latter approach is that it will work with any two types that are convertible to Employee. Alternatively, you can create a comparator functor, instead of operator <(), and pass that the map's constructor.

Lastly, use the insert() member function of std::map<> to insert the new employees. std::map<> also has operator []() defined, and it allows you to insert into the map. The insert() function will not insert the element if the element is already in the map, whereas operator []() will update the element if it already exists.

11 Comments

If he's using a map that's keyed on a char * then overloading < or making a functor isn't really necessary. If he switches to a set (which it sounds like he might want to) then this makes sense.
@Niki but his map is not keyed on char*. It's keyed on Employee.
@wilhelmtell - his question is a little ambiguous. It sounds like he wants a map of Employees keyed on their last name, not a map of something else keyed on Employees (if that is the case you are absolutely right). Most likely he should switch to a set in which case you are also completely correct.
"It sounds like he wants a map of Employees keyed on their last name" that's right.
@Roy Ah. In that case you want to use a std::set<>, because otherwise it's an utter waste of memory (if each string is duplicated) or violation of information hiding if the keys point at the strings of the objects.
|
1

You could create a "functor" which overrides operator(), taking references to two of your objects and returning a boolean of obj1 < obj2.

For example:

class EmployeeComparator { public: bool operator()(const Employee& emp1, const Employee& emp2) { return strcmp(emp1.lastName, emp2.lastName) < 0; } } 

When you create your std::map, you then pass EmployeeComparator as the comparison object, like so:

std::map<Employee, T, EmployeeComparator> m; 

Other posters' ideas of overriding the < operator will work too, but with that method you have pick a single criteria to sort by. With my way, you could have one map that sorts by last name, another that sorts by employee ID, etc. With each map you'd pass a different functor as your sorter.

Keep in mind that with my way, if you are trying to sort by a private field, declare your sorting functor as a friend class of the class to be sorted.

Comments

1

As Philip Potter has written in comments, you should definetely use std::string. Because two different char* declared at several places/files in your cpp code WON'T have the same addresses ! As a char* is nothing but an integer, you will have several char* keys for one and only one same lastname, and this is not what you want.

go this way:

std::map<std::string,YourType> yourMap; std::string strMyLastName = "Rolland"; YourType aValue; yourMap[strMyLastName ] = aValue; 

3 Comments

@Roy, and please why couldnt you use std::string ? ? ? I am really serious when I tell you that you will have dupplicate key entree for the same lastnames. And if you write C++, use std::strings and not char* as most as you can, and unless forced to do the contrary.
i'm more pissed off than you about this, it's my stupid teach assistant who force us to do this. " lastName must be char*, all the other fields can be string"
:-))) so your teacher wants you to experiment with dupplicate keys ;-)
1

To add to what wheaties said, if the Employee object contains its own key, you should probably use a set. In order to use the set, you are going to have to explicitly define a method of comparison for the Employee object. There are two ways of doing that, either define operator< for the object:

class Employee { public: bool operator<(const Employee &rhs) { return strcmp(lastName, rhs.lastName) < 0; } ... }; 

Or you can define a functor that you tell the set to use for comparison:

struct EmployeeLessThan { bool operator()(const Employee &lhs, const Employee &rhs) { return strcmp(lhs.lastName, rhs.lastName) < 0; } }; std::set<Employee, EmployeeLessThan> myEmployees; 

Edit: One VERY important thing to keep in mind is that a set stores all of it's items as const. It does this because it's possible that a change to an element in the set could change the order of the elements and set isn't capable of detecting this and reordering. This can be problematic if you want to update any of the employees contained in the set. The best way around this problem is to declare any of the data members of Employee that you might want to change as mutable. This will let you change their values even when it's const.

Edit2: If you decide to continue using a map and the key is a char *, then keep in mind that by default the map is going to compare two char *s by the value of their pointer, not the string they point to. The best thing to do in this case is to use std::string instead of char *. Alternatively, you can define a functor to pass to the map:

struct CharStarLessThan { bool operator()(const char *lhs, const char *rhs) { return strcmp(lhs, rhs) < 0; } }; std::map<char *, Employee, CharStarLessThan> myEmployees; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.