Contents of boost::shared_ptr as key for set? - c++

I'd like to store a series of pointers in an std::unordered_set. I'd like the hash function to be based not on the memory address, but on some values contained within the actual object referenced by the pointer.
e.g. (using std and boost namespaces for readability)
class MyClass {
...
//some values I want to use as the key for the hash
double a;
int b;
int c;
}
typedef shared_ptr<MyClass> MyClassPtr;
set<MyClassPtr> mySet;
I'm not worried about combining the actual hash values (found answer here: http://www.boost.org/doc/libs/1_47_0/doc/html/hash/combine.html), but rather dereferencing the shared_ptr to get the keys.
The other concern I have is that the == operator is already definied for boost::shared_ptr, and I was wondering if this would cause problems with my approach? I'd need to test equality against the object, not the pointer.
Storing pointers in the set because several other parts of the code are referencing the objects via their own pointers. Any alternative approaches are welcomed as well.
Thanks

What's the problem? Define a hash function and equality and on you go:
struct MyClassHash
{
inline std::size_t operator()(const MyClassPtr & p)
{
return 4; // prone to hash collisions, improve on this
}
};
struct MyClassEqual
{
inline bool operator()(const MyClassPtr & p, const MyClassPtr & q)
{
return false; // implement
}
};
typedef std::unordered_set<MyClassPtr, MyClassHash, MyClassEqual> MySet;
Note that the two functors (hash and equality) have to be written as classes; free functions don't work. (The container keeps a private instance of the functors around.) This is somewhat annoying, but since you'll only be doing this once, it shouldn't be so bad.
Normally I'd recommend specializing std::hash and std::equals, but I'd hesitate to do that with something so general as a shared pointer, since it might easily confuse others who don't expect those specializations.

Related

How to get numeric data from a member function pointer for a hash? [duplicate]

How can i hash (std::tr1::hash or boost::hash) a c++ pointer-to-member-function?
Example:
I have several bool (Class::*functionPointer)() (not static) that point to several diferent methods of the class Class and i need to hash those pointer-to-member-function.
How can i do that?
Also how can i compare (std::less) those member function pointers so i can store them in a std::set?
All C++ objects, including pointers to member functions, are represented in memory as an array of chars. So you could try:
bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));
Now treat ptrptr as pointing to an array of (sizeof(bool (Class::*)())) bytes, and hash or compare those bytes. You can use unsigned char instead of char if you prefer.
This guarantees no false positives - in C++03, pointers to member functions are POD, which means among other things that they can be copied using memcpy. This implies that if have the same byte-for-byte values, then they are the same.
The problem is that the storage representation of member function pointers could include bits which do not participate in the value - so they will not necessarily be the same for different pointers to the same member function. Or the compiler might, for some obscure reason, have more than one way of pointing to the same function of the same class, which are not byte-wise equal. Either way you can get false negatives. You'll have to look into how member function pointers actually work on your implementation. It must implement operator== for member function pointers somehow, and if you can find out how then you can probably figure out an order and a hash function.
That's potentially hard: member function pointers are awkward, and the storage is likely to include different amounts of non-participating "slack space" according to what kind of function is pointed to (virtual, inherited). So you'll probably have to interact quite significantly with your compiler's implementation details. This article might help get you started: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
A cleaner alternative might be to do a linear search through an array in order to "canonicalise" all your function pointers, then compare and hash based on the position of the "canonical" instance of that function pointer in your array. Depends what your performance requirements are. And even if there are requirements, does the class (and its derived classes) have so many functions that the linear search will take that long?
typedef bool (Class::*func)();
vector<func> canon;
size_t getIndexOf(func fn_ptr) {
vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
if (it != canon.end()) return it - canon.begin();
canon.push_back(func);
return canon.size() - 1;
}
I could not cast the pointer (in Microsoft compiler 2010)as described in previous answer but this works for me:
static string fmptostr(int atype::*opt)
{
char buf[sizeof(opt)];
memcpy(&buf,&opt,sizeof(opt));
return string(buf,sizeof(opt));
}
About bitwise identity of the pointer, it can be bitwise so it seems if appropriate compiler switches are used. At least this is true for Microsoft compiler E.g
using #pragma pointers_to_members
and a switch.../vmg
If your member function pointer is unique, which is true in most of cases for callback-based subscriptions, then you can use the tick with type_index, which uniqueness is guaranteed by uniqueness of type (i.e. Class::Method) in your program, and it is suitable to be stored in unordered_map, i.e.
struct MyEvent {
using fn_t = std::function<void(MyEvent &)>;
using map_t = std::unordered_map<std::type_index, fn_t>;
template <typename Handler>
void subscribe(Object& obj, Handler&& handler) {
fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
(obj.*handler)(event);
}
std::type_index index = typeid(Handler);
subscribers.emplace(std::move(index), std::move(fn));
}
void fire() {
for(auto& pair: subscribers) {
auto& fn = pair.second;
fn(*this);
}
}
map_t subscribers;
}
And the subscription and fire event example:
MyEvent event;
MyObject obj = ...;
event.subscribe(obj, &MyObject::on_event );
...
event.fire();
So, example above gives you class/method uniqueness, and if you need object/method uniqueness, then you should have an struct, which provides combined hash, assuming that there is std::hash<MyObject> and there is already std::hash<std::type_index> for a member function pointer.

Using STL containers with a class containing its own key

I have an object, which can be identified by its name, and I want to place it in one of the STL containers.
class MyClass {
public:
//getters and setters, other functions
private:
std::string name;
//other member variables
};
So at first I thought that the usage of map-like structures is irrelevant in my case, because in those structures the identifier (the key) is separated from the class itself. Using a map I must return the name variable and copy it "outside" the class (waste of memory and illogical, breaking OOP rules).
My next shot was the usage of set-like structures. In this case I only have the key field, where I load my whole object. Using this method I must overload my <, > and == operators in order to use an object as key. I can even make a functor for hashing if I use unordered_set, it works just fine. The problem here is that I cannot use the container functions as I would with a map. This is valid mapInstance.find("example"), and this is not setInstance.find("example"). I must create an object with the member variable name set to "example" and pass it to the find() function. The problem with this solution is that the other member variables in my class are duplicated and not used. I even tried overloading the <, > and == operators for std::string and MyClass classes, which works fine if I use them like this stringInstance < MyClassInstance, but the container functions are unusable (I even tried to overload the functor to work with a string with no success).
Can you suggest me a simple way (or a way), how to solve this problem with std::set or std::map(maybe others)?
In std::map the key cannot be a reference (as I know), and I don't know how to resolve it with std::set.
Note: The problem with storing a pointer in a map's key field is that if we change our mind and use unordered_map instead of map, the hash will be calculated based on the pointer, not based on the string (the hash function can be overridden, but it seems very complicated for a simple task).
Thanks for your help!
You should ask yourself what your requirements for your container are.
Things to consider are:
How many objects will usually be in the container
What are the memory constraints
How often will objects be searched for and which complexity is acceptable?
A std::map has some requirements which might conflict with your class. E.g. the key is not allowed to be changed once an element is added to the map. However, your class might change the name at every time. From this consideration it should become clear that a std::map cannot work with a reference to a string as the key.
In the simplest case, you might consider using a std::list and std::find_if with a predicate to check for a special name. This would have O(n) complexity.
Sometimes you have to build upon what's given to get the desired results. I'd suggest that what you're looking for is a specialized adapter for your use case.
Here's a very basic implementation that you can build upon. In many cases, the cache locality you get from using std::vector will give better performance than using a standard container that provides a similar feature set.
Given a simple type and some helper operators:
struct Obj
{
int key;
std::string name;
};
bool operator<(const Obj& lhs, const Obj& rhs)
{
return lhs.key < rhs.key;
}
bool operator==(const Obj& lhs, int rhs)
{
return lhs.key == rhs;
}
bool operator<(const Obj& lhs, int rhs)
{
return lhs.key < rhs;
}
We can devise a simple flat_map class that provides the basic complexity guarantees of a map, but will meet your requirement of finding objects by key without constructing a value type (like you need to with a set). Insertion gives more complexity, but lookups are of similar complexity. If lookups occur much more frequently then insertions (which is the case most of the time) this can work well.
class flat_map
{
public:
using container_type = std::vector<Obj>;
// insert object into the set
// complexity varies based on length of container
void insert(Obj&& obj)
{
container_.emplace_back(std::move(obj));
std::sort(container_.begin(), container_.end());
}
// find with O(log N) complexity
container_type::iterator find(int key)
{
auto it = std::lower_bound(container_.begin(), container_.end(), key);
if(it != container_.end() && *it == key)
return it;
return container_.end();
}
private:
container_type container_;
};
Example usage:
int main()
{
flat_map obj;
obj.insert({1, "one"});
obj.insert({2, "two"});
obj.insert({3, "three"});
auto it = obj.find(2);
std::cout << it->key << ' ' << it->name << '\n';
}
You can extend the flat_map adapter in any way you see fit. Adding the required overloads to meet your requirements, templatizing the parameters (allocator, comparisons, storage types, etc.).

Is it possible to use elements of a different type than contained in a std::set to perform search and deletion?

Let's say I have the following:
struct MetadataThingy {
void *actual_thingy;
int some_metadata;
int more_metadata;
bool operator<(MetadataThingy const& other) const {
return actual_thingy < other.actual_thingy;
}
};
where actual_thingy points to some data of importance and I want the container ordered by the value of actual_thingy rather than the value of the element pointed at, but I need to store some other data about it, so I created the wrapper class MetadataThingy with a comparator that only considers the value of the actual_thingy pointer (rather than using a container of void *)
Now, given the following code:
std::set<MetadataThingy> thingy_set;
void test() {
MetadataThingy m1 { nullptr, 5, 20 };
MetadataThingy m2 { &m1, 1, 2 };
MetadataThingy m3 { &m2, 6, 0 };
thingy_set.insert(m1);
thingy_set.insert(m2);
thingy_set.insert(m3);
MetadataThingy m;
m = *thingy_set.find(m2); // OK.
m = *thingy_set.find(static_cast<void *>(&m2)); // Nope. Can't use a pointer.
}
Since each MetadataThingy can be uniquely identified by the pointer value it stores and is ordered by the pointer value, it would make sense to find/delete objects simply by using a void * as the key. As it currently stands, though, I would have to create a dummy MetadataThingy each time I search for an element, which feels really kludgy. I've already considered using just a map with pointers as key and MetadataThingy as value but since each MetadataThingy must also contain the pointer anyway, this feels a bit redundant. So, is there a way to use an element of a type other than that stored in a set to find or delete values in the set, given that elements of the two types are mutually comparable and that elements of one type can be uniquely mapped into the other ( void * and MetadataThingy are isomorphic)? (I didn't include any in the above code, but suppose there are operator overloads for comparing void * and MetadataThingy in any order.)
A little background on the problem I'm trying to solve, just in case anyone can recommend a better approach: I need to order a collection by multiple criteria, so I have several MetadataThingy containers, all sorted by different criteria. "Metadata" in this case would be stuff I need to track the positions of the elements in all containers so that I can do fast removal. This would sound like a perfect job for boost multi-index containers, but the ordering of these elements is constantly changing, which AFAIK would mean it won't work.
As of C++14, std::set has templated versions of its lookup functions find, lower_bound, etc. They allow you to pass any object for comparison, as long as the comparer supports it.
This means you can directly pass your void* to find, as long as the comparer supports comparing MetadataThingy and void*.
For more information, see http://en.cppreference.com/w/cpp/container/set/find.
To understand the limitation regarding Compare::is_transparent, I found this StackOverflow question very helpful.
You can do this by using std::find_if and providing a predicate functor.
#include <algorithm>
struct Predicate
{
void const * const ptr_;
explicit Predicate(const void* ptr) : ptr_(ptr) {}
bool operator()(const MetadataThingy& other)
{
return ptr_ == other.actual_thingy;
}
};
m = *std::find_if(thingy_set.begin(), thingy_set.end(), Predicate(&m2));
You can use the iterator returned by std::find_if to remove the element from the set by passing it to set::erase.
No, the signature of map<>::find requires you pass in the key type.
There is, however, a relatively simple workaround. Use boost::optional or std::tr2::optional (from C++1y) to store your non-key data.
struct MetadataThingy {
void* pBlah;
optional<rest_of_stuff> rest;
static MetadataThingy searcher( void* );
MetadataThingy(...);
};
then call MeatadataThingy::searcher to generate your key value.
Another approach would be to store smart (unique probably) pointers to sub-interfaces, each of which has a "get full data" method. Then, when you want to do a search, create a stub sub-interface that returns nullptr on "get full data".
struct MetadataFull;
struct MetadataRoot {
virtual MetadataFull* get() = 0;
virtual MetadataFull const* get() const = 0;
virtual ~MetadataRoot() {}
};
template<typename T>
struct MetadataFinal: virtual MetadataRoot {
static_assert( std::is_base_of< T, MetadataFinal<T> >::value, "CRTP failure" );
virtual MetadataFull* get() { return static_cast<T*>(this); }
virtual MetadataFull const* get() const { return static_cast<T const*>(this); }
};
struct MetadataStub: virtual MetadataRoot {
virtual MetadataFull* get() { return nullptr; }
virtual MetadataFull const* get() const { return nullptr; }
};
struct MetaDataA: virtual MetaDataRoot {
void* pBlah;
};
struct MetaDataFull: MetaDataA, MetadataFinal<MetaDataFull> {
// unsorted data
};
struct MetaDataAStub: MetaDataA, MetaDataStub {};
now, this can be done with virtual functions but not virtual inheritance with a bit of finagling if you really need it.
The library does not support the behavior that you ask for, although I have seen other people request the same thing (i.e. providing a templated member function find in ordered associative containers that would use a cross comparator), although this is infrequent.
Your type is unusual in that only one of the member attributes takes part on the value of the object (i.e. is used in the comparison). The compiler cannot know that only some of the members (or which of the members) are part of the value and which are not. although it might be that the objects are not really comparable and you just hammered operator< as a simple way of enabling the use in associative containers.
If that is the case, consider dropping the operator< that does not really compare the MetaThingy objects and also change the data structure to be a std::map<void*,MetaThingy>, which would make the design cleaner at the cost of an extra void* per stored object --it might also be the case that the void* is inside the MetaThingy for the lookup in the set... in which case it might even make more sense and you could provide std::map<void*,MetaInfo>.

C++11 shared_pointer constness within stl containers

I have the following problem and I wonder whether there's a better way to solve it:
class myObj {
public:
typedef std::shared_ptr<myObj> handle;
typedef std::shared_ptr<const myObj> const_handle;
int someMethod() { ... }
int someConstMethod() const { ... }
};
Now what I need is a container class that somehow allows you to modify or read a collection of myObj depending on its own constness, like so:
class myCollection {
public:
typedef std::list<myObj::handle> objList;
typedef std::list<myObj::const_handle> const_objList;
inline objList& modify() { return _obl; }
// it would be nice to do this, but it won't compile as
// objList and const_objList are completely different types
inline const_objList& read() const { return _obl; } // doh! compile error...
// returning a const objList won't help either as it would return non-const
// handles, obviously.
// so I am forced to do this, which sucks as i have to create a new list and copy
void read(const_objList &l) {
std::for_each(
_obl.begin(),
_obl.end(),
[&l] (myObj::handle &h) { l.push_back(h); }
// ok as handle can be cast to const_handle
); // for_each
}
private:
objList _obl;
};
So this solution actually works as a const myCollection would only allow you to get a list of const_handle which only allows you to call non-modifying methods of myObj (GOOD).
The problem is that the "read" method is really ugly (BAD).
Another method would be to expose somehow the list methods and return const_handle and handle as needed but it's a lot of overhead, especially if you want to use something more complex than a list.
Any idea?
A list-of-pointers-to-T is not a list-of-pointers-to-constant-T.
std::list<std::shared_ptr<int>> a;
std::list<std::shared_ptr<const int>>& ra = a; // illegal but imagine it's not
std::shared_ptr<const int> x = std::make_shared<const int>(42);
ra.push_back(x); // totally legal, right?
++**a.begin(); // oops... just incremented a const int
Now a list-of-pointers-to-T is, conceptually, a constant-list-of-constant-pointers-to-constant-T, but std::list<std::shared_ptr<T>> does not support such a deep const propagation. const std::list<std::shared_ptr<T>> contains constant pointers to non-constant objects.
You can write your own variant of list<> or your own variant of shared_ptr<> that have such support. It probably won't be very easy though. A const_propagating_shared_ptr is probably the easier of the two. It would have to encapsulate an std::shared_ptr<T> object and forward almost everything to it as-is. As opposed to std::shared_ptr<T> it would have separate const and non-const versions of operator->, operator*() and get().
Given what you stated that you want to accomplish, I don't think that your solution is too bad. Imagine that some other code may be modifying the internal collection, like adding or removing values. Returning a copy of the current state of the collection is safe for client code, since it can work on the copy, without the danger of element being deleted in the meantime. But I digress, this is getting into threading issues and may not be relevant.
You could use prettier:
inline const_objList read() const
{
const_objList cl(_obl.begin(), _obl.end());
return cl;
}
However, I do think that your problems derive from mixing two types of constness: constness of the members of the collection versus the constness of the collection itself.
Instead of Modify and Read methods, that deal with the list as a whole, I would try exposing const and non-const iterators to internal list, through corresponding const and non-const methods returning said iterators.
But this immediately begs the question: why then have myCollection in the first place?
Creating entirely new collection type around std::list doesn't seem needed, unless you get a lot of proverbial bang for the buck from other, added functionality that is not visible in your sample.
You can then make your added functionality free methods that take std::list of your handles as the input. Not everything requires an object and operations on objects need not necessarily be member methods, unless access to private data is required.
You mentioned maybe using another container instead of the list. But your class, as is, won't do it, unless you have a template, where template parameter can be one of STL containers.
Which then implies that you should expose iterators.
Namely, if you foresee changing the internal collection type, you would want to make the public interface to myCollection transparent regarding the collection type. Otherwise, clients will have to recompile each time you change your mind about the internal implementation.
EDIT -----
Finally, if implementing iterators (while interesting and most correct) is too much, why not go for simple getters like in this SO post:
smart pointer const correctness
I'll quote the topmost answer by RĂ¼diger Stevens (it assumes vector instead of list):
template <typename T>
class MyExample
{
private:
vector<shared_ptr<T> > data;
public:
shared_ptr<const T> get(int idx) const
{
return data[idx];
}
shared_ptr<T> get(int idx)
{
return data[idx];
}
void add(shared_ptr<T> value)
{
data.push_back(value);
}
};

How to hash and compare a pointer-to-member-function?

How can i hash (std::tr1::hash or boost::hash) a c++ pointer-to-member-function?
Example:
I have several bool (Class::*functionPointer)() (not static) that point to several diferent methods of the class Class and i need to hash those pointer-to-member-function.
How can i do that?
Also how can i compare (std::less) those member function pointers so i can store them in a std::set?
All C++ objects, including pointers to member functions, are represented in memory as an array of chars. So you could try:
bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));
Now treat ptrptr as pointing to an array of (sizeof(bool (Class::*)())) bytes, and hash or compare those bytes. You can use unsigned char instead of char if you prefer.
This guarantees no false positives - in C++03, pointers to member functions are POD, which means among other things that they can be copied using memcpy. This implies that if have the same byte-for-byte values, then they are the same.
The problem is that the storage representation of member function pointers could include bits which do not participate in the value - so they will not necessarily be the same for different pointers to the same member function. Or the compiler might, for some obscure reason, have more than one way of pointing to the same function of the same class, which are not byte-wise equal. Either way you can get false negatives. You'll have to look into how member function pointers actually work on your implementation. It must implement operator== for member function pointers somehow, and if you can find out how then you can probably figure out an order and a hash function.
That's potentially hard: member function pointers are awkward, and the storage is likely to include different amounts of non-participating "slack space" according to what kind of function is pointed to (virtual, inherited). So you'll probably have to interact quite significantly with your compiler's implementation details. This article might help get you started: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
A cleaner alternative might be to do a linear search through an array in order to "canonicalise" all your function pointers, then compare and hash based on the position of the "canonical" instance of that function pointer in your array. Depends what your performance requirements are. And even if there are requirements, does the class (and its derived classes) have so many functions that the linear search will take that long?
typedef bool (Class::*func)();
vector<func> canon;
size_t getIndexOf(func fn_ptr) {
vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
if (it != canon.end()) return it - canon.begin();
canon.push_back(func);
return canon.size() - 1;
}
I could not cast the pointer (in Microsoft compiler 2010)as described in previous answer but this works for me:
static string fmptostr(int atype::*opt)
{
char buf[sizeof(opt)];
memcpy(&buf,&opt,sizeof(opt));
return string(buf,sizeof(opt));
}
About bitwise identity of the pointer, it can be bitwise so it seems if appropriate compiler switches are used. At least this is true for Microsoft compiler E.g
using #pragma pointers_to_members
and a switch.../vmg
If your member function pointer is unique, which is true in most of cases for callback-based subscriptions, then you can use the tick with type_index, which uniqueness is guaranteed by uniqueness of type (i.e. Class::Method) in your program, and it is suitable to be stored in unordered_map, i.e.
struct MyEvent {
using fn_t = std::function<void(MyEvent &)>;
using map_t = std::unordered_map<std::type_index, fn_t>;
template <typename Handler>
void subscribe(Object& obj, Handler&& handler) {
fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
(obj.*handler)(event);
}
std::type_index index = typeid(Handler);
subscribers.emplace(std::move(index), std::move(fn));
}
void fire() {
for(auto& pair: subscribers) {
auto& fn = pair.second;
fn(*this);
}
}
map_t subscribers;
}
And the subscription and fire event example:
MyEvent event;
MyObject obj = ...;
event.subscribe(obj, &MyObject::on_event );
...
event.fire();
So, example above gives you class/method uniqueness, and if you need object/method uniqueness, then you should have an struct, which provides combined hash, assuming that there is std::hash<MyObject> and there is already std::hash<std::type_index> for a member function pointer.