C++ how to insert array into hash set? - c++

I need to insert a 1D array into the hashset.
But I got error while compiling.
#include <stdio.h>
#include <stdlib.h>
#include <hash_set.h>
using namespace std;
int hash_comp(const int* state1,const int* state2) {
int result = 0;
for (i = 0; i < 16; i++)
{
if (state1[i] != state2[i]) {
result = -1;
}
}
return result;
}
struct eqArray
{
bool operator()(const int* a1,const int* a2) const
{
return hash_comp(a1,a2) == 0;
}
};
hash_set<int*,hash<int*>,eqArray> closelist;
int main(int argc, char** argv)
{
const int sn[16] = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
closelist.insert(sn);
return 0;
}
/usr/include/c++/4.2.1/ext/hashtable.h: In member function 'size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num_key(const _Key&, size_t) const [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]':
/usr/include/c++/4.2.1/ext/hashtable.h:599: instantiated from 'size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num(const _Val&, size_t) const [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hashtable.h:1006: instantiated from 'void __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::resize(size_t) [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hashtable.h:437: instantiated from 'std::pair<__gnu_cxx::_Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>, bool> __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::insert_unique(const _Val&) [with _Val = int*, _Key = int*, _HashFcn = __gnu_cxx::hash<int*>, _ExtractKey = std::_Identity<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
/usr/include/c++/4.2.1/ext/hash_set:197: instantiated from 'std::pair<typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Tp>, _EqualKey, _Alloc>::const_iterator, bool> __gnu_cxx::hash_set<_Value, _HashFcn, _EqualKey, _Alloc>::insert(const typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Tp>, _EqualKey, _Alloc>::value_type&) [with _Value = int*, _HashFcn = __gnu_cxx::hash<int*>, _EqualKey = std::equal_to<int*>, _Alloc = std::allocator<int*>]'
src/ods2.cpp:677: instantiated from here

If you use a std::array<int, 16> instead of int*, all your problems will go away. If you have no C++11 compiler, you can use boost::array instead. Also, replace hash_set with unordered_set.
It appears there is no specialization of std::hash for std::arrays, so I wrote my own:
#include <unordered_set>
#include <array>
namespace std
{
template<typename T, size_t N>
struct hash<array<T, N> >
{
typedef array<T, N> argument_type;
typedef size_t result_type;
result_type operator()(const argument_type& a) const
{
hash<T> hasher;
result_type h = 0;
for (result_type i = 0; i < N; ++i)
{
h = h * 31 + hasher(a[i]);
}
return h;
}
};
}
std::unordered_set<std::array<int, 16> > closelist;
int main()
{
std::array<int, 16> sn = {1,2,3,4,5,6,0,8,9,10,11,12,13,14,7,15};
closelist.insert(sn);
}

You didn’t post the actual error message, only the trace. That said, it’s probably because your set uses non-const int* while your data is const.
That said, I’d suggest using unordered_set instead of hash_set(either from std::tr1 if your compiler supports that, or from std if your compiler supports C++11 or from Boost), and heed Fred’s advice of using an {std,boost}::array instead of a raw pointer.

I don't think that there exists a specialized hash<int*>. I added this:
namespace __gnu_cxx{ //I'm not sure what compiler version you used,
//mine wanted this
template<>
struct hash<const int*>{
size_t operator()(const int*a) const{
size_t r = 0;
for (int i=0;i<16;i++)
r = (r<<1) ^ a[i]; //not sure if it makes sense as a hash.
return r;
}
};
}
I also put in some consts and it compiles.

Related

How to use std::unordered_multiset with a custom class?

I am trying to declare an unordered_multiset which is going to contain objects of a custom class, but I can't find any examples out there for this. Following the documentation, it seems that I need to declare an operator== in the class, alongside the hashing function(operator() const) which, as per the documentation:
Accepts a single parameter of type Key.
Returns a value of type std::size_t that represents the hash value of the parameter.
Does not throw exceptions when called.
For two parameters k1 and k2 that are equal, std::hash<Key>()(k1) == std::hash<Key>()(k2).
For two different parameters k1 and k2 that are not equal, the probability that
std::hash<Key>()(k1) == std::hash<Key>()(k2) should be very small, approaching 1.0/std::numeric_limits<std::size_t>::max().
The code looks like this in a very simplistic way:
Class MyClass:
// comparator
bool MyClass::operator ==(const MyClass b) const {
return (string == b.getString()); // compares two strings
}
// hash operation
size_t MyClass::operator()() const {
return hash<string>()(string); // bases the hash on the string
}
main.cpp:
unordered_multiset<MyClass> s1;
// Also tried: unordered_multiset<MyClass, std::hash<MyClass>, std::equal_to<MyClass>> s1;
However, in the instatiation of the unordered_multiset the compiler (GCC) will complain about the hash functions (Tupla is the name of MyClass, and there are 1000+ lines, I included a few of them):
error: use of deleted function ‘std::unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset() [with _Value = Tupla; _Hash = std::hash<Tupla>; _Pred = std::equal_to<Tupla>; _Alloc = std::allocator<Tupla>]’
78 | unordered_multiset<Tupla> s1;
| ^~
/usr/include/c++/10/bits/unordered_set.h:949:7: note: ‘std::unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset() [with _Value = Tupla; _Hash = std::hash<Tupla>; _Pred = std::equal_to<Tupla>; _Alloc = std::allocator<Tupla>]’ is implicitly deleted because the default definition would be ill-formed:
949 | unordered_multiset() = default;
/usr/include/c++/10/bits/unordered_set.h:949:7: error: use of deleted function ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable() [with _Key = Tupla; _Value = Tupla; _Alloc = std::allocator<Tupla>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Tupla>; _H1 = std::hash<Tupla>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, false>]’
In file included from /usr/include/c++/10/unordered_set:46,
/usr/include/c++/10/bits/hashtable.h:451:7: note: ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable() [with _Key = Tupla; _Value = Tupla; _Alloc = std::allocator<Tupla>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Tupla>; _H1 = std::hash<Tupla>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, false>]’ is implicitly deleted because the default definition would be ill-formed:
451 | _Hashtable() = default;
An allocator is also mentioned as a pre-requisite for the unordered_multiset, but I neither understand it not I am sure whether that should be included (or how).
What did I miss?
you can replace string with your struct i guess:
#include <bits/stdc++.h>
using namespace std;
// Custom Hash Functor that will compute the hash on the
// passed string objects length
struct StringHashBySize {
public:
size_t operator()(const std::string & str) const {
int size = str.length();
return std::hash<int>()(size);
}
};
// Custom comparator that compares the string objects by length
struct StringEqualBySize {
public:
bool operator()(const std::string & str1, const std::string & str2) const {
if (str1.length() == str2.length())
return true;
else
return false;
}
};
int main() {
// Declaring unordered_multiset with Custom Hash Function and comparator
unordered_multiset<std::string, StringHashBySize, StringEqualBySize> multiset;
return 0;
}
The simplest way of doing this would probably be a helper class for the hash implementation:
struct MyClassHash
{
const std::hash<std::string> m_stringHash {};
size_t operator()(const MyClass& value) const
{
return m_stringHash(value.getString());
};
};
and use this for hashing:
std::unordered_multiset<MyClass, MyClassHash> s1;
I btw recommend passing the parameter as reference to operator==, not by copy:
bool operator==(const MyClass& other) const;

Reference to vector element in allocator aware class calls copy constructor

I have a class that contains a vector of vector. It is allocator aware. When trying to call the operator[] to store elements in a reference, Visual Studio 2015 fails to compile, AppleClang (latest) is fine with it.
I am unsure whether this is a bug or not, which compiler is right, or if there is some undefined behaviour somewhere in my code.
Here is a concise example, with everything as simple as possible.
#include <cstdlib>
#include <memory>
#include <new>
#include <vector>
/* Allocator */
template <class T>
struct my_allocator {
typedef T value_type;
my_allocator() = default;
template <class U>
constexpr my_allocator(const my_allocator<U>&) noexcept {
}
T* allocate(std::size_t n) {
if (n > std::size_t(-1) / sizeof(T))
throw std::bad_alloc();
if (auto p = static_cast<T*>(std::malloc(n * sizeof(T))))
return p;
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t) noexcept {
std::free(p);
}
};
template <class T, class U>
bool operator==(const my_allocator<T>&, const my_allocator<U>&) {
return true;
}
template <class T, class U>
bool operator!=(const my_allocator<T>&, const my_allocator<U>&) {
return false;
}
/* Example Element */
struct X {
X() = default;
X(X&&) = default;
X& operator=(X&&) = default;
X(const X&) = delete;
X& operator=(const X&) = delete;
int test = 42;
};
/* Example Container Class */
template <class T, class Allocator = std::allocator<T>>
struct vec_of_vec {
using OuterAlloc = typename std::allocator_traits<
Allocator>::template rebind_alloc<std::vector<T, Allocator>>;
vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
std::vector<T, Allocator>& operator[](size_t i) {
return data[i];
}
std::vector<std::vector<T, Allocator>, OuterAlloc> data;
};
/* Trigger Error */
int main(int, char**) {
my_allocator<X> alloc;
vec_of_vec<X, my_allocator<X>> test(alloc);
X& ref_test = test[0][0]; // <-- Error Here!
printf("%d\n", ref_test.test);
return 0;
}
VS tries to use the copy constructor of X.
error C2280: 'X::X(const X &)': attempting to reference a deleted function
function main.cpp(42): note: see declaration of 'X::X'
Is there something I am missing with the use of allocators and allocator_traits?
GCC error sheds light on what's going on, potentially same in VS2015 case.
In file included from memory:65,
from prog.cc:2:
bits/stl_uninitialized.h: In instantiation of '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = __gnu_cxx::__normal_iterator<const X*, std::vector<X, my_allocator<X> > >; _ForwardIterator = X*; _Allocator = my_allocator<X>]':
bits/stl_vector.h:454:31: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = X; _Alloc = my_allocator<X>]'
bits/alloc_traits.h:250:4: required from 'static std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > = void]'
bits/alloc_traits.h:344:16: required from 'static decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = void]'
bits/stl_uninitialized.h:351:25: required from '_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, _Allocator&) [with _ForwardIterator = std::vector<X, my_allocator<X> >*; _Size = long unsigned int; _Tp = std::vector<X, my_allocator<X> >; _Allocator = my_allocator<std::vector<X, my_allocator<X> > >]'
bits/stl_vector.h:1466:33: required from 'void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >]'
bits/stl_vector.h:421:9: required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >; std::vector<_Tp, _Alloc>::allocator_type = my_allocator<std::vector<X, my_allocator<X> > >]'
prog.cc:59:42: required from 'vec_of_vec<T, Allocator>::vec_of_vec(const Allocator&) [with T = X; Allocator = my_allocator<X>]'
prog.cc:76:46: required from here
bits/stl_uninitialized.h:275:25: error: no matching function for call to '__gnu_cxx::__alloc_traits<my_allocator<X>, X>::construct(my_allocator<X>&, X*, const X&)'
__traits::construct(__alloc, std::__addressof(*__cur), *__first);```
Wandbox
if we go from bottom to top we see:
vec_of_vec constructor
filling vector<vector> by 10 copies of empty inner vector
construction of copies
Despite of the fact that inner vector is empty, its copy constructor requires that the type it contains is copy-constructible.
P.S.
I don't know how clang overcomes this. Potentially it recognises that vector<vector> if filled with default value (if constructor with passed allocator instance still qualifies as default) and so instead of copying uses default construction
EDIT:
To fix the error replace
vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
by
vec_of_vec(const Allocator& alloc = Allocator{})
{
data.resize(10); // here we don't `fill` it by copies but default-construct 10 instances
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
or version for stateful allocator:
vec_of_vec(const Allocator& alloc = Allocator{}):
data(OuterAlloc(alloc))
{
for (int i = 0; i < 10; ++i) {
data.emplace_back(alloc);
data.back().resize(42);
}
}

How to pass normal param as well as template param in a template function in C++?

I have a template function (as follows) in a namespace called myNamespace:
template <typename setX>
void getRandomItems(NaturalNumber size, setX &random, setX &items)
{
assert(size <= items.size());
//set of randomly selected indices for items
set<NaturalNumber> index;
NaturalNumber r, i;
while(index.size() < size)
{
r = unifRand(0,items.size()-1);
index.insert(r);
}
typename setX::iterator it, sit = items.begin();
for(i = 0, it = index.begin(); it != index.end(); it ++)
{
//find the r-th elt in index
r = *it;
for(; i < r; i ++)
sit++;
random.insert(*sit);
}
}
However whenever I call this function I get these errors:
generic.h: In function ‘void myNamespace::getRandomItems(NaturalNumber, setX&, setX&) [with setX = std::set<std::basic_string<char> >, NaturalNumber = long unsigned int]’:
synthetic-graph.C:87:55: instantiated from here
generic.h:74:32: error: no match for ‘operator=’ in ‘it = index.std::set::begin [with _Key = long unsigned int, _Compare = std::less<long unsigned int>, _Alloc = std::allocator<long unsigned int>, std::set<_Key, _Compare, _Alloc>::iterator = std::_Rb_tree_const_iterator<long unsigned int>]()’
/usr/include/c++/4.5/bits/stl_tree.h:224:5: note: candidate is: std::_Rb_tree_const_iterator<std::basic_string<char> >& std::_Rb_tree_const_iterator<std::basic_string<char> >::operator=(const std::_Rb_tree_const_iterator<std::basic_string<char> >&)
synthetic-graph.C:87:55: instantiated from here
generic.h:74:32: error: no match for ‘operator!=’ in ‘it != index.std::set<_Key, _Compare, _Alloc>::end [with _Key = long unsigned int, _Compare = std::less<long unsigned int>, _Alloc = std::allocator<long unsigned int>, std::set<_Key, _Compare, _Alloc>::iterator = std::_Rb_tree_const_iterator<long unsigned int>]()’
/usr/include/c++/4.5/bits/stl_tree.h:291:7: note: candidate is: bool std::_Rb_tree_const_iterator<_Tp>::operator!=(const std::_Rb_tree_const_iterator<_Tp>::_Self&) const [with _Tp = std::basic_string<char>, std::_Rb_tree_const_iterator<_Tp>::_Self = std::_Rb_tree_const_iterator<std::basic_string<char> >]
generic.h:77:4: error: cannot convert ‘const std::basic_string<char>’ to ‘NaturalNumber’ in assignment
I have tried all combinations but no luck, please help me!!!
setX is not a set of NaturalNumbers so the iterators aren't compatible when you say it = index.begin(). You could possibly make it an iterator of set<NaturalNumber> instead, I can't quite make out what you really want to do here.
Also I noticed that in your inner loop you don't do any checks to make sure sit doesn't run off the end of its set.
You're trying to assign incompatible iterators.
Perhaps you meant
set<NaturalNumber>::iterator it;
typename setX::iterator sit = items.begin();
instead of
typename setX::iterator it, sit = items.begin();

gcc workaround while using shared_ptr to insert in std::set

This code fails to compile using g++ 4.2.1 but works fine under vc++ v8.
#include <set>
typedef std::set<int *> IntPtrSet;
IntPtrSet iptrSet;
typedef std::set<shared_ptr<int>> IntPtrSet2;
IntPtrSet2 iptrSet2;
void AddIntegers(int& x)
{
iptrSet.insert(&x);
iptrSet2.insert(&x);
}
shared_ptr is similar to boost::shared_ptr or tr1::shared_ptr.
It emits the following errors,
No matching function for call to std::allocator<shared_ptr<int>>::construct(int**, const shared_ptr<int>&)
No matching function for call to std::allocator<shared_ptr<int> >::destroy(int **)
Did anyone encounter such error before? If yes, what is the workaround.
Here is the complete error message:
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:402: error: no matching function for call to 'std::allocator<shared_ptr<int> >::destroy(int**)'
/Users/mark/Templates/Function/main.cpp:188: instantiated from here
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:380: error: no matching function for call to 'std::allocator<shared_ptr<int> >::construct(int**, const shared_ptr<int>&)'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/ext/new_allocator.h:106: note: candidates are: void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = shared_ptr<int>]
Complete Template Instantiation stack:
/Developer/usr/bin/gcc-4.2 -x c++ -arch x86_64 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Wreturn-type -Wunused-variable -isysroot
/Developer/SDKs/MacOSX10.6.sdk -mfix-and-continue -fvisibility-inlines-hidden -mmacosx-version-min=10.6 -gdwarf-2 -iquote /Users/mark/Templates/Function/build/Function.build/Debug/Function.build/Function-generated-files.hmap - I/Users/mark/Templates/Function/build/Function.build/Debug/Function.build/Function-own-target-headers.hmap - I/Users/mark/Templates/Function/build/Function.build/Debug/Function.build/Function-all- target-headers.hmap -iquote /Users/mark/Templates/Function/build/Function.build/Debug/Function.build/Function-project- headers.hmap -F/Users/mark/Templates/Function/build/Debug - I/Users/mark/Templates/Function/build/Debug/include - I/Users/mark/Templates/Function/build/Function.build/Debug/Function.build/DerivedSources/x86 _64 - I/Users/mark/Templates/Function/build/Function.build/Debug/Function.build/DerivedSources -c /Users/mark/Templates/Function/main.cpp -o /Users/mark/Templates/Function/build/Function.build/Debug/Function.build/Objects- normal/x86_64/main.o
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h: In member function 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_destroy_node(std::_Rb_tree_node<_Val>*) [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]':
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:1327: instantiated from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_erase(std::_Rb_tree_node<_Val>*) [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:594: instantiated from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::~_Rb_tree() [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_set.h:141: instantiated from 'std::set<_Key, _Compare, _Alloc>::set() [with _Key = shared_ptr<int>, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Users/mark/Templates/Function/main.cpp:181: instantiated from here
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:402: error: no matching function for call to 'std::allocator<shared_ptr<int> >::destroy(int**)'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/ext/new_allocator.h:110: note: candidates are: void __gnu_cxx::new_allocator<_Tp>::destroy(_Tp*) [with _Tp = shared_ptr<int>]
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h: In member function 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(const _Val&) [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]':
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:840: instantiated from 'typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, const _Val&) [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:988: instantiated from 'std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = shared_ptr<int>, _Val = shared_ptr<int>, _KeyOfValue = std::_Identity<shared_ptr<int> >, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_set.h:307: instantiated from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = shared_ptr<int>, _Compare = std::less<shared_ptr<int> >, _Alloc = std::allocator<shared_ptr<int> >]'
/Users/mark/Templates/Function/main.cpp:188: instantiated from here
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/bits/stl_tree.h:380: error: no matching function for call to 'std::allocator<shared_ptr<int> >::construct(int**, const shared_ptr<int>&)'
/Developer/SDKs/MacOSX10.6.sdk/usr/include/c++/4.2.1/ext/new_allocator.h:106: note: candidates are: void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = shared_ptr<int>]
Here is the complete code:
#include <iostream>
template <class T>
class shared_ptr
{
private:
T* m_p;
public:
shared_ptr() throw() : m_p(NULL){}
shared_ptr( const shared_ptr<T>& p) throw()
{
m_p = p;
}
shared_ptr( T* p) throw()
{
m_p = p;
}
~shared_ptr() throw()
{
m_p = NULL;
}
T* operator=(const shared_ptr<T>& p) throw()
{
if (m_p != p.m_p)
{
m_p = p;
}
return m_p;
}
T* operator=(T* p) throw()
{
if (m_p != p)
{
m_p = p;
}
return m_p;
}
operator T*() const throw()
{
return m_p;
}
T& operator*() const throw()
{
return *m_p;
}
T** operator&() throw()
{
return &m_p;
}
bool operator!() const throw()
{
return (m_p == NULL);
}
bool operator<(T* p) const throw()
{
return m_p < p;
}
bool operator!=(int nNull) const throw()
{
return !operator==(nNull);
}
bool operator==( int nNull) const throw()
{
return m_p == NULL;
}
bool operator!=( T* p) const throw()
{
return !operator==(p);
}
bool operator==( T* p) const throw()
{
return m_p == p;
}
void CopyTo( T** pp) const throw()
{
*pp = m_p;
}
void Release() throw()
{
T* p = m_p;
if (p)
{
m_p = NULL;
}
}
void Attach( T* p) throw()
{
m_p = p;
}
T* Detach() throw()
{
T* p = m_p;
m_p = NULL;
return p;
}
};
#include <set>
typedef std::set<int *> IntPtrSet;
IntPtrSet iptrSet;
typedef std::set<shared_ptr<int> > IntPtrSet2;
IntPtrSet2 iptrSet2;
void AddIntegers(int& x)
{
iptrSet.insert(&x);
shared_ptr<int> intPtr(new int(3));
iptrSet2.insert(intPtr);
}
int main (int argc, char * const argv[]) {
char c;
std::cin >> c;
return 0;
}
Also on the Dinkumware site the code compiled successfully. It fails to compile using g++ as mentioned earlier.FYI, I have pasted the result from the Dinkumware website (http://www.dinkumware.com/exam/default.aspx) below.
Your code has been compiled with the Microsoft Visual Studio 2005 C++ compiler using
the Dinkum C++ library from the Dinkum Compleat Libraries for VC++ package.
This is the compiler output using the code above in a file named
sourceFile.cpp:
sourceFile.cpp
size sourceFile.exe :
6144t + 3584 .rdata + 512d = 10240 (2800)
Code compiled successfully!
The executable generated was 11 KB.
Thanks a lot
Regards,
Mark
For (obvious) reason, there is not implicit conversion from T* to shared_ptr<T>.
For example, the following code fails:
int i = 3;
shared_ptr<int> ptr;
ptr = &i;
There is a good reason for that: the shared_ptr OWNS the resources it points to. You cannot blindly throw something into a shared_ptr to get free memory management, you have to make sure that the object is not already owned by something else.
The solution is to use either the constructor or a builder:
shared_ptr<int> ptr(new int(3));
shared_ptr<int> ptr = shared_ptr<int>(new int(3));
shared_ptr<int> made = make_shared<int>(3);
The last method leads to a slightly more compact pointer, though the difference is unlikely to affect you.
I would stress that your example is fishy. Ownership is better enforced right at creation time. In a function like such, chances are someone else has acquired the ownership already and that you're creating a Big Bad Bug.
Your shared_ptr implementation seems very unusual.
Compared to boost/tr1, you have extra converting operators for T** and T*. Implicitly converting to the underlying pointer type (T*) is only going to confuse the compiler.
After I commented out those methods, I had to fix the copy constructor to actually copy member-wise rather than abusing the converting operator. It still won't work as a shared pointer because there's no reference counting.
Then I had to fix operator< to take const shared_ptr<T>& p again because the implicit conversions were causing this to compile, but confusing the compiler on the std::set later on. It got confused because it was trying to construct a shared_ptr but the operator& (I think) caused it to degrade to T** so the type didn't match the type inside the container.
With those changes I was able to get it to successfully compile with g++ 4.2.
EDIT:
Well, I was able to write a custom allocator that compiles but it doesn't seem terribly clean and may not even work in all cases.
template <class T>
class sh_ptr_alloc : public std::allocator<T>
{
public:
typedef size_t size_type;
sh_ptr_alloc() throw() { }
template<typename Tp1>
sh_ptr_alloc(const sh_ptr_alloc<Tp1>&) throw() { }
template<typename Tp1>
struct rebind
{ typedef sh_ptr_alloc<Tp1> other; };
template <class Tp1>
void
deallocate(Tp1* p, size_type)
{ ::operator delete(p); }
template <class Tp1>
void
construct(Tp1** p, const shared_ptr<Tp1>& val)
{ ::new(p) shared_ptr<int>(val); }
template <class Tp1>
void
destroy(Tp1** p) { }
};
The set is then:
typedef std::set<shared_ptr<int>, std::less<shared_ptr<int> >, sh_ptr_alloc<shared_ptr<int> > > IntPtrSet2;
Looks like it's having trouble with the conversion from int* to shared_ptr. I think the workaround is fairly simple:
shared_ptr<int> intPtr(&x);
iptrSet2.insert(intPtr);
void AddIntegers(int& x)
{
...
iptrSet2.insert(&x);
This probably fails, because there is no implicit conversion form int* to boost::shared_ptr<int>. You'll have to construct it manually (and beware: for one object, only one shared_ptr can be constructed; other pointers must be creaied as copies of this one "master" shared pointer).

simple C++ hash_set example

I am new to C++ and STL. I am stuck with the following simple example of a hash set storing custom data structures:
#include <iostream>
#include <ext/hash_set>
using namespace std;
using namespace __gnu_cxx;
struct trip {
int trip_id;
int delta_n;
int delta_secs;
trip(int trip_id, int delta_n, int delta_secs){
this->trip_id = trip_id;
this->delta_n = delta_n;
this->delta_secs = delta_secs;
}
};
struct hash_trip
{
size_t operator()(const trip t)
{
hash<int> H;
return H(t.trip_id);
}
};
struct eq_trip
{
bool operator()(const trip t1, const trip t2) {
return (t1.trip_id==t2.trip_id) &&
(t1.delta_n==t2.delta_n) &&
(t1.delta_secs==t2.delta_secs);
}
};
int main()
{
hash_set<trip, hash_trip, eq_trip> trips;
trip t = trip(3,2,-1);
trip t1 = trip(3,2,0);
trips.insert(t);
}
when I try to compile it, I get the following error message:
/usr/include/c++/4.2.1/ext/hashtable.h: In member function ‘size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num_key(const _Key&, size_t) const [with _Val = trip, _Key = trip, _HashFcn = hash_trip, _ExtractKey = std::_Identity<trip>, _EqualKey = eq_trip, _Alloc = std::allocator<trip>]’:
/usr/include/c++/4.2.1/ext/hashtable.h:599: instantiated from ‘size_t __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::_M_bkt_num(const _Val&, size_t) const [with _Val = trip, _Key = trip, _HashFcn = hash_trip, _ExtractKey = std::_Identity<trip>, _EqualKey = eq_trip, _Alloc = std::allocator<trip>]’
/usr/include/c++/4.2.1/ext/hashtable.h:1006: instantiated from ‘void __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::resize(size_t) [with _Val = trip, _Key = trip, _HashFcn = hash_trip, _ExtractKey = std::_Identity<trip>, _EqualKey = eq_trip, _Alloc = std::allocator<trip>]’
/usr/include/c++/4.2.1/ext/hashtable.h:437: instantiated from ‘std::pair<__gnu_cxx::_Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>, bool> __gnu_cxx::hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>::insert_unique(const _Val&) [with _Val = trip, _Key = trip, _HashFcn = hash_trip, _ExtractKey = std::_Identity<trip>, _EqualKey = eq_trip, _Alloc = std::allocator<trip>]’
/usr/include/c++/4.2.1/ext/hash_set:197: instantiated from ‘std::pair<typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Value>, _EqualKey, _Alloc>::const_iterator, bool> __gnu_cxx::hash_set<_Value, _HashFcn, _EqualKey, _Alloc>::insert(const typename __gnu_cxx::hashtable<_Value, _Value, _HashFcn, std::_Identity<_Value>, _EqualKey, _Alloc>::value_type&) [with _Value = trip, _HashFcn = hash_trip, _EqualKey = eq_trip, _Alloc = std::allocator<trip>]’
try.cpp:45: instantiated from here
/usr/include/c++/4.2.1/ext/hashtable.h:595: error: passing ‘const hash_trip’ as ‘this’ argument of ‘size_t hash_trip::operator()(trip)’ discards qualifiers
What am I doing wrong?
You should investigate using the STL's TR1 extension namely
unordered_map
unordered_set
unordered_multimap
unordered_mutliset
Most modern C++ compilers ship with these extensions, hence there is no need to use a non-standard class such as hash_set etc.
http://en.wikipedia.org/wiki/Unordered_map_%28C%2B%2B_class%29
http://publib.boulder.ibm.com/infocenter/comphelp/v9v111/index.jsp?topic=/com.ibm.xlcpp9.aix.doc/standlib/stl_unordered_map.htm
http://www.cplusplus.com/reference/unordered_set/unordered_set/
So close! The last error in your output reveals your hash_trip routine should be declared const:
size_t operator()(const trip t) const // note the ending 'const'
{
//...
}
You'll probably need to do the same thing for eq_trip. Also, I would recommend passing the arguments to these functions by constant reference to avoid an unnecessary copy of the data you're passing:
size_t operator()(const trip& t) const // note the '&'
{
//...
}