C++ Use of deleted function error - c++

I'm getting a lot of use of deleted function error. I just changed the pointer of weighted_pointer to unique_ptr. But I can't realize why I'm getting the error, any tip?
The likeatree is a DAG structure which can point to another struct or an element of stdDeque based on mask value.
The weight of weighted_pointer has mutable keyword because doesn't change where in the set will be.
#include <deque>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
#include <memory>
#include <chrono>
using namespace std;
struct likeatree{
unsigned int mask : 3;
void * a;
void * b;
};
struct weighted_pointer{
mutable int weight;
unique_ptr<likeatree> ptr;
};
struct ptrcomp{
bool operator()(const weighted_pointer & lhs, const weighted_pointer & rhs) {
if(lhs.ptr->mask < rhs.ptr->mask)
return true;
if(lhs.ptr->mask > rhs.ptr->mask)
return false;
if(lhs.ptr -> a < rhs.ptr->a)
return true;
if(lhs.ptr->a > rhs.ptr->a)
return false;
return lhs.ptr->b < rhs.ptr->b;
}
};
vector<likeatree *> treeVector;
deque<bool> stdDeque(3);
vector<vector<bool>> boolMatrix{{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
set<weighted_pointer,ptrcomp> stdSet;
int main(){
srand(time(NULL));
likeatree * first_pointer = new likeatree{0,&input[0],nullptr};
likeatree * second_pointer = first_pointer;
unique_ptr<likeatree> tmp(first_pointer);
weighted_pointer wp;
wp.weight = 1;
wp.pointer = move(tmp);
stdSet.insert(move(wp));
// I'd like to do it inline(or more but with variables that end of scope here), but this don't work. (And i don't keep a copy of the pointer)
// stdSet.insert(move(weighted_pointer{1,move(make_unique<likeatree>(*new likeatree{0,&input[0],nullptr}))}));
return 0;
}
Edit: Changed code with a single case of the problem
Edit: Solved. Missing a dereference when using make_unique.

Your struct here:
struct weighted_pointer{
mutable int weight;
unique_ptr<likeatree> ptr;
};
contains a std::unique_ptr. A std::unique_ptr cannot be copied, so your entire weighted_pointer cannot be copied as well.
There are three places in your code where you attempt to copy it, which causes the errors you see:
bool operator()(const weighted_pointer lhs, const weighted_pointer rhs) {
Must be:
bool operator()(weighted_pointer const& lhs, weighted_pointer const& rhs) {
stdSet.insert(tmp);
This could theoretically be fixed by:
stdSet.insert(std::move(tmp));
However, you then cannot use tmp anymore, which you do, not only in the same loop but also in the loop below. So you must find a different solution altogether. Perhaps use emplace. Or restructure your code entirely.
auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer temp){ return temp.ptr.get() == treeVector[i]; });
Must be:
auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer const& temp){ return temp.ptr.get() == treeVector[i]; });
For VC++ 2013, the std::move fix will not suffice. You will have to add an explicit move constructor to your struct:
struct weighted_pointer{
mutable int weight;
unique_ptr<likeatree> ptr;
weighted_pointer() = default;
weighted_pointer(weighted_pointer&& src) :
weight(std::move(src.weight)),
ptr(std::move(src.ptr))
{
}
};
VC++ 2015 fixes this problem. More information: Default Move Constructor in Visual Studio 2013 (Update 3)

Your weighted_pointer is non-copyable because it contains a non-copyable member (the unique_ptr), so you have to pass it by const reference to your comparator function.
bool operator()(const weighted_pointer& lhs, const weighted_pointer& rhs)
This is because if you pass it by value (as it is currently written), it will try to make a function-local copy.
You also cannot do this because you are trying to copy tmp, which as I just said that struct is non-copyable.
for(unsigned int i = 0; i < stdDeque.size(); i++){
tmp.ptr.reset(new likeatree{0,&stdDeque[i],nullptr});
stdSet.insert(tmp);
}
You can use emplace to construct a weighted_pointer in-place instead
for(unsigned int i = 0; i < stdDeque.size(); i++){
stdSet.emplace(1, std::make_unique<likeatree>(0,&stdDeque[i],nullptr));
}

When I compile the code above, the compiler says:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from 31791982.cpp:7:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘_InputIterator std::__find_if(_InputIterator, _InputIterator, _Predicate, std::input_iterator_tag) [with _InputIterator = std::_Rb_tree_const_iterator<weighted_pointer>; _Predicate = main()::__lambda0]’:
/usr/include/c++/4.8/bits/stl_algo.h:4465:41: required from ‘_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<weighted_pointer>; _Predicate = main()::__lambda0]’
31791982.cpp:55:124: required from here
So look at line 55 - what's happening:
auto it = find_if(stdSet.begin(),stdSet.end(),[&](weighted_pointer temp){ return temp.ptr.get() == treeVector[i]; });
We're trying to copy a weighted_pointer from the array into the lambda's temp. But really, we'd be happy with a const ref, so replace with const weighted_pointer& and compile again:
/usr/include/c++/4.8/bits/stl_tree.h: In instantiation of ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = weighted_pointer; _Val = weighted_pointer; _KeyOfValue = std::_Identity<weighted_pointer>; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = weighted_pointer]’:
/usr/include/c++/4.8/bits/stl_tree.h:1377:47: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = const weighted_pointer&; _Key = weighted_pointer; _Val = weighted_pointer; _KeyOfValue = std::_Identity<weighted_pointer>; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>]’
/usr/include/c++/4.8/bits/stl_set.h:463:29: required 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 value_type&) [with _Key = weighted_pointer; _Compare = ptrcomp; _Alloc = std::allocator<weighted_pointer>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<weighted_pointer>; std::set<_Key, _Compare, _Alloc>::value_type = weighted_pointer]’
31791982.cpp:49:26: required from here
Line 49 is:
stdSet.insert(tmp);
We can't copy tmp into the set. If we weren't going to re-use tmp we could move it instead:
for(unsigned int i = 0; i < stdDeque.size(); i++){
weighted_pointer tmp;
tmp.weight = 1;
tmp.ptr.reset(new likeatree{0,&stdDeque[i],nullptr});
stdSet.insert(std::move(tmp));
}
That then leaves us with an easy fix for ptrcomp::operator() which needs to accept its arguments by const reference.

Related

How to solve ambiguity in operator overloading embedded inside a struct?

In the following code, the g++ compiler surprisingly cannot decide which operator to use when they are embedded in a struct to serve as a comparator argument in a set:
#include <string>
#include <set>
struct KeyWord {
std::string str;
int qt;
KeyWord(const std::string aKw = "", const int aQt = 0) : str(aKw), qt(aQt) {}
};
struct CompareKeywords {
bool operator() (const std::string& left, const std::string& right) const {
if (left.size() > right.size()) return true;
else if (left.size() < right.size()) return false;
else return (left < right);
}
bool operator() (const KeyWord& left, const KeyWord& right) {
if (left.str.size() > right.str.size()) return true;
else if (left.str.size() < right.str.size()) return false;
else return (left.str < right.str);
}
};
int main() {
std::set<std::string, CompareKeywords> a;
std::set<KeyWord, CompareKeywords> b;
std::string s("_s_");
KeyWord k("_k_", 1);
a.insert(s);
b.insert(k);
}
Here is the compiler output:
g++ oa.cpp
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = std::basic_string<char>]’:
/usr/include/c++/4.9/bits/stl_tree.h:1498:47: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/4.9/bits/stl_set.h:502:29: required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::basic_string<char>; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<std::basic_string<char> >; std::set<_Key, _Compare, _Alloc>::value_type = std::basic_string<char>]’
oa.cpp:28:13: required from here
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*]’:
/usr/include/c++/4.9/bits/stl_tree.h:1502:38: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/4.9/bits/stl_set.h:502:29: required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::basic_string<char>; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<std::basic_string<char> >; std::set<_Key, _Compare, _Alloc>::value_type = std::basic_string<char>]’
oa.cpp:28:13: required from here
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
The last lines show the ambiguity where the compiler shows two candidates.
Why this ambiguity exist? How should I supress it?
It looks like some builds of gcc have this peculiar feature of printing these messages out of the blue. For example all builds on coliru do this.
These messages are not errors because the object file is produced, and they are not warnings because -Werror doesn't turn them into errors. They look rather like a compiler bug. Obviously one cannot suppress these non-warnings with compiler flags.
Same exact versions of gcc on my machine don't print any messages with this code. They do print regular (tagged with the coloured "warning", non-suppressible, but turnable-to-error) warnings with similar code.
On coliru, making the second operator() const suppresses the messages.
Two separate struct with only one operator in each of them dedicated to a type solves the problem:
#include <string>
#include <set>
struct KeyWord {
std::string str;
int qt;
KeyWord(const std::string aKw = "", const int aQt = 0) : str(aKw), qt(aQt) {}
};
struct CompareStrings {
bool operator() (const std::string& left, const std::string& right) const {
if (left.size() > right.size()) return true;
else if (left.size() < right.size()) return false;
else return (left < right);
}
};
struct CompareKeywords {
bool operator() (const KeyWord& left, const KeyWord& right) {
if (left.str.size() > right.str.size()) return true;
else if (left.str.size() < right.str.size()) return false;
else return (left.str < right.str);
}
};
int main() {
std::set<std::string, CompareStrings> a;
std::set<KeyWord, CompareKeywords> b;
std::string s("_s_");
KeyWord k("_k_", 1);
a.insert(s);
b.insert(k);
}
There was an error in the initial code:
bool operator() (const std::string& left, const std::string& right) const {
bool operator() (const KeyWord& left, const KeyWord& right) {
Suppressing the const at the end of the first declaration, or adding one to the second one solves the problem. But still, I don't understand why the compiler was confused.
So, either:
bool operator() (const std::string& left, const std::string& right) {
bool operator() (const KeyWord& left, const KeyWord& right) {
or:
bool operator() (const std::string& left, const std::string& right) const {
bool operator() (const KeyWord& left, const KeyWord& right) const {
works.
Note: Wheither a const function or not is discussed here.
Since I want overloading, both functions are expected to have the same behaviour, so const to both or none. If I would have liked different behaviours with one with const and the other without (in the case I would have had some struct members I would have wanted to modify), the second solution below with separate struct for each operator definition would be the solution.

Trouble with operator < overloading in C++

I'm just learning operator overloading and am trying to add two vertices of my custom class to a set. This causes strange errors and my attempt at < overloading didn't work.
Can someone explain what's wrong?
My Vertex class:
class Vertex{
public:
int i, j;
set<Vertex> adj; //adjacent vertices
Vertex(){
i = j = -1;
}
~Vertex(){
adj.clear();
}
//end constructors and destructors
void setPos(int row, int col){
i = row;
j = col;
}//end setPos()
/** must overload for set<Vertex> to function */
bool operator < (const Vertex &o){
if(i < o.i)
return true;
if(i > o.i)
return false;
return j < o.j;
}
};//END class Vertex
But calling this function in main causes strange output in terminal and an error:
/** connect v1 and v2 such that they are adjacent */
void addEdge(Vertex v1, Vertex v2){
v1.adj.insert(v2);
v2.adj.insert(v1);
}//END addEdge()
Error:
In file included from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\string:48:0,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\locale_cla
sses.h:40,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\ios_base.h
:41,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\ios:42,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\ostream:38,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\iostream:39,
from FileMaze.cc:2:
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h: In instantiation
of 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = V
ertex]':
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1321:11: required f
rom 'std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree
<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_
type&) [with _Key = Vertex; _Val = Vertex; _KeyOfValue = std::_Identity<Vertex>;
_Compare = std::less<Vertex>; _Alloc = std::allocator<Vertex>; std::_Rb_tree<_K
ey, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = Vertex]'
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1374:47: required f
rom 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _Ke
yOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = Vertex;
_Val = Vertex; _KeyOfValue = std::_Identity<Vertex>; _Compare = std::less<Vertex
>; _Alloc = std::allocator<Vertex>]'
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_set.h:463:29: required fro
m 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare,
typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Com
pare, _Alloc>::insert(const value_type&) [with _Key = Vertex; _Compare = std::le
ss<Vertex>; _Alloc = std::allocator<Vertex>; typename std::_Rb_tree<_Key, _Key,
std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_ite
rator = std::_Rb_tree_const_iterator<Vertex>; std::set<_Key, _Compare, _Alloc>::
value_type = Vertex]'
FileMaze.cc:47:18: required from here
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h:235:20: error: pa
ssing 'const Vertex' as 'this' argument of 'bool Vertex::operator<(const Vertex&
)' discards qualifiers [-fpermissive]
{ return __x < __y; }
^
make: *** [FileMaze.o] Error 1
The operator< function needs to be a const member function. Change it to
bool operator < (const Vertex &o) const;
I recommend you to check this page of c++ FAQ.
In fact when you overload functions like Less operator, you don't change the objects and so It is expected that to be overloaded as const member function :
bool operator < (const Vertex &o) const {
^~~~~
}

Find in a map using the base class with a boost::shared_ptr

I'm looking for a way to find an element inside a map using the base class (the code bellow is just a basic example):
#include <map>
#include <boost/shared_ptr.hpp>
class Base {
public:
Base(int v) : id(v) {};
int id;
};
class Derived : public Base {
public:
Derived(int v) : Base(v) {};
};
int main()
{
std::map<boost::shared_ptr<Derived>, double> m;
m.insert(std::make_pair(boost::shared_ptr<Derived>(new Derived(1)), 10));
m.insert(std::make_pair(boost::shared_ptr<Derived>(new Derived(2)), 20));
auto b1 = boost::shared_ptr<Base>(new Base(1));
m.find(b1);
return 0;
}
Basically, I want to compare the id attribute. The errors returned by the compiler are the following:
main.cpp: In function 'int main()':
main.cpp:35:14: error: no matching function for call to 'std::map<boost::shared_ptr<Derived>, double>::find(boost::shared_ptr<Base>&)'
m.find(b1);
^
main.cpp:35:14: note: candidates are:
In file included from /usr/include/c++/4.8/map:61:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/stl_map.h:820:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&) [with _Key = boost::shared_ptr<Derived> _Tp = double; _Compare = std::less<boost::shared_ptr<Derived> > _Alloc = std::allocator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::key_type = boost::shared_ptr<Derived>]
find(const key_type& __x)
^
/usr/include/c++/4.8/bits/stl_map.h:820:7: note: no known conversion for argument 1 from 'boost::shared_ptr<Base>' to 'const key_type& {aka const boost::shared_ptr<Derived>&}'
/usr/include/c++/4.8/bits/stl_map.h:835:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&) const [with _Key = boost::shared_ptr<Derived> _Tp = double; _Compare = std::less<boost::shared_ptr<Derived> > _Alloc = std::allocator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::key_type = boost::shared_ptr<Derived>]
find(const key_type& __x) const
^
/usr/include/c++/4.8/bits/stl_map.h:835:7: note: no known conversion for argument 1 from 'boost::shared_ptr<Base>' to 'const key_type& {aka const boost::shared_ptr<Derived>&}'
If you want to use your map for lookup by id, you need to pass in an appropriate comparison function so that the map sorts its keys by id instead of the default operator < (which, I believe, compares ownership block addresses with boost::shared_ptr arguments).
So change the map like this:
struct Less_id
{
bool operator() (const boost::shared_ptr<Derived> &lhs, const boost::shared_ptr<Derived> &rhs) const
{
return lhs->id < rhs->id;
}
};
typedef std::map<boost::shared_ptr<Derived>, double, Less_id> Map;
Map m;
This will sort the map accordingly, but still not allow lookup by Base pointer. To do that, you can write your own function above std::lower_bound:
Map::const_iterator find_base(const Map &map, const boost::shared_ptr<Base> &base)
{
auto it = std::lower_bound(
map.begin(), map.end(), base,
[](const Map::value_type &lhs, const boost::shared_ptr<Base> &rhs)
{ return lhs.first->id < rhs->id; }
);
if (it != map.end() && it->first->id == base->id)
return it;
else
return map.end();
}
std::lower_bound() is used to keep the logarithmic complexity std::map::find() offers.
Live example
Use an
std::map<boost::shared_ptr<Derived>, double, std::less<boost::shared_ptr<Base>>>
Edit: I am ahead of the times - this only works for C++14.
There are two issues to overcome. The first is that you want to search for a Base in a collection of Deriveds. The second is that you want to compare by value rather than by address. The other answers are neglecting this second point. Try std::find_if:
auto b1 = boost::shared_ptr<Base>(new Base(1));
auto itFound = std::find_if(m.begin(), m.end()
[=](const std::pair<boost::shared_ptr<Derived>, double>& pair)
{
// omitting null checks for this example
return pair.first->id == b1->id;
});
And if the requirement is really just to find a key with the given id, you could make it simpler:
int queryKey = 1;
auto itFound = std::find_if(m.begin(), m.end()
[=](const std::pair<boost::shared_ptr<Derived>, double>& pair)
{
return pair.first->id == queryKey;
});
Now, as noted in the comments, this will give you linear rather than map's usual logarithmic lookup time. If the map is small it won't matter, but if this is an issue, you could use std::lower_bound instead of find_if. Note that this would also require adding a custom comparer so you could ensure the map's sort order was based on id. For example:
struct Compare
{
bool operator()(const boost::shared_ptr<Derived>& l,
const boost::shared_ptr<Derived>& r) const
{
// omitting null checks for this example
return l->id < r->id;
}
};
std::map<boost::shared_ptr<Derived>, double, Compare> m;
This is because boost::shared_ptr's operator < is not what you want, you need a delegation to the Derived class's operator <.
use std::map<_Key, _Tp, _Compare>
for example:
std::map<boost::shared_ptr<Derived>, double, compare_func()> m;
As you are looking for an object Base which can only be in the map if it is of type Derived you can simply do this:
boost::shared_ptr<Derived> d1 = boost::dynamic_pointer_cast<Derived>(b1);
if(d1) {
m.find(d1);
} else {
// not in the map
}
As you use std::shared_ptr<Derived> as a key, another possibility would be to actually use pointers to the base class instead:
Use
std::map<boost::shared_ptr<Base>, double> m;
instead of
std::map<boost::shared_ptr<Derived>, double> m;
and everything works as expected.
Btw, you are missing a virtual destructor in Base!

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).

Problem with std::map and std::pair

I have a small program I want to execute to test something
#include <map>
#include <iostream>
using namespace std;
struct _pos{
float xi;
float xf;
bool operator<(_pos& other){
return this->xi < other.xi;
}
};
struct _val{
float f;
};
int main()
{
map<_pos,_val> m;
struct _pos k1 = {0,10};
struct _pos k2 = {10,15};
struct _val v1 = {5.5};
struct _val v2 = {12.3};
m.insert(std::pair<_pos,_val>(k1,v1));
m.insert(std::pair<_pos,_val>(k2,v2));
return 0;
}
The problem is that when I try to compile it, I get the following error
$ g++ m2.cpp -o mtest
In file included from /usr/include/c++/4.4/bits/stl_tree.h:64,
from /usr/include/c++/4.4/map:60,
from m2.cpp:1:
/usr/include/c++/4.4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = _pos]’:
/usr/include/c++/4.4/bits/stl_tree.h:1170: 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 = _pos, _Val = std::pair<const _pos, _val>, _KeyOfValue = std::_Select1st<std::pair<const _pos, _val> >, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
/usr/include/c++/4.4/bits/stl_map.h:500: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = _pos, _Tp = _val, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
m2.cpp:30: instantiated from here
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
m2.cpp:9: note: candidates are: bool _pos::operator<(_pos&)
$
I thought that declaring the operator< on the key would solve the problem, but its still there.
What could be wrong?
Thanks in advance.
The problem is this:
bool operator<(_pos& other)
Should be this:
bool operator<(const _pos& other) const {
// ^^^^ ^^^^^
Without the first const, the right-hand side of the comparison (b in a < b) cannot be const, since without const the function may modify its argument.
Without the second const, the left-hand side of the comparison (a in a < b) cannot be const, since without const the function may modify this.
Internally, the key's of a map are always const.
It should be noted that you should prefer to use nonmember functions. That is, better is a free-function:
bool operator<(const _pos& lhs, const _pos& rhs)
{
return lhs.xi < rhs.xi;
}
In the same namespace as your class. (For our example, just underneath it.)
By the way, in C++ there is no need to prefix the declaration of a struct type variable with struct. This is perfect, and preferred:
_pos k1 = {0,10};
_pos k2 = {10,15};
_val v1 = {5.5};
_val v2 = {12.3};
(Though your type names are admittedly named in an unorthodox manner. :P)
Lastly, you should prefer the make_pair utility function for making pairs:
m.insert(std::make_pair(k1,v1));
m.insert(std::make_pair(k2,v2));
It saves you from having to write out the types for the pair, and is generally easier to read. (Especially when longer type names come along.)
Signature of the less than operator needs to be bool operator<(const _pos& other) const, otherwise map can not use this operator in const functions since this member function is declared as non-const.
I think that your definition of operator< is wrong - the right hand side (argument in this case) should be marked const and it should be a const member function, e.g.
bool operator<(const _pos& other) const{
return this->xi < other.xi;
}