std::set design issue

Started by
20 comments, last by loufoque 14 years, 11 months ago
im having a problem with std::set ive got different sets where all the types inherit a class "Identifiable" with an std::string Id() function... looks somehting like this

struct IDCompare	
{ 
bool operator()(const IdentifiablePtr& lhs, const IdentifiablePtr& rhs) const	
{ 
return strcmp(lhs->Id().c_str(), rhs->Id().c_str())  < 0 ; 
} 
};

std::set<boost::shared_ptr<SomeType>, IDCompare>

however when i want to find an object in the set based on the "Id" i get into problems...

			template<typename T> 
			boost::shared_ptr<T> Find(const std::string& id) const
			{
				boost::shared_ptr<T> dummy(new T(id));
				SetType::const_iterator it = mySet.find(dummy);
				return it != Get<T>().end() ? *it : boost::shared_ptr<T>();
			}

i have to create a "dummy" object of the type in order to find the real object... these objects can be pretty large so i dont want to create a dummy everytime... the reason im using a set instead of a map is that i want to be able to use for_each functions and similar easily... how shoudl i go about this?
Advertisement
struct IDCompare
{
bool operator()(const IdentifiablePtr& lhs, const IdentifiablePtr& rhs) const
{
return lhs->Id() < rhs->Id();
}
bool operator()(const IdentifiablePtr& lhs, const std::string& rhs) const
{
return lhs->Id() < rhs;
}
bool operator()(const std::string& lhs, const IdentifiablePtr& rhs) const
{
return lhs < rhs->Id();
}
};
...
std::string str("hi");
mySet.find(str);
return strcmp(lhs->Id().c_str(), rhs->Id().c_str())  < 0 ; 


This would be somewhat simpler as:

return lhs->Id() < rhs->Id();


As to the dummy, at least it doesn't have to be allocated dynamically. But perhaps a map would be better (do the objects even need to know their ID if the map could know that?)
Quote:Original post by visitor
return strcmp(lhs->Id().c_str(), rhs->Id().c_str())  < 0 ; 


This would be somewhat simpler as:

return lhs->Id() < rhs->Id();


As to the dummy, at least it doesn't have to be allocated dynamically. But perhaps a map would be better (do the objects even need to know their ID if the map could know that?)


i think a map would work better... however there are problems when i want to use algorithms on the collection... since the map iterator works on key value pairs... do u know of any adapters for maps?
Quote:Original post by Dragon_Strike
there are problems when i want to use algorithms on the collection... since the map iterator works on key value pairs
What kinds of problems? It's just that it seems relatively easy to extract the value from a key-value pair?

Quote:Original post by incin
struct IDCompare
{
bool operator()(const IdentifiablePtr& lhs, const IdentifiablePtr& rhs) const
{
return lhs->Id() < rhs->Id();
}
bool operator()(const IdentifiablePtr& lhs, const std::string& rhs) const
{
return lhs->Id() < rhs;
}
bool operator()(const std::string& lhs, const IdentifiablePtr& rhs) const
{
return lhs < rhs->Id();
}
};
...
std::string str("hi");
mySet.find(str);


that doesnt work...?

cannot convert parameter 1 from 'const std::string' to 'const boost::shared_ptr<T> &'
Quote:Original post by dmatter
Quote:Original post by Dragon_Strike
there are problems when i want to use algorithms on the collection... since the map iterator works on key value pairs
What kinds of problems? It's just that it seems relatively easy to extract the value from a key-value pair?


well the problem is that it adds complexity and makes it harder to work with... id rather add some extra code here than having to extract the value with every use case

EDIT:

another reason i want the objects to know their ids is that i can optimize it later by precaluclating a hash function and use that for lookups rather than running a hash function for each lookup...

[Edited by - Dragon_Strike on May 2, 2009 4:11:07 PM]
Sorry, thought I did that before. But it obviously won't work, as find() must take a value_type. I'd also vote for using a map. You can always use helper functions to hide the map implementation.
You need to use the right container for the job, and when the key is logically separate from the value, you use a map.

In your case, the value "knows" about it's own key, which is OK, but the key is obviouslly still logically separate, since you want to be able to search just on key.
Quote:
But it obviously won't work, as find() must take a value_type.


And I thought I had learned something new...

Probably to make it more efficient with a set, you can avoid the dynamic allocation because boost::shared_ptr can also hold pointers to stack objects.

This topic is closed to new replies.

Advertisement