stl vector::insert difference in Windows and linux? - c++

there. I've searched my question around here but failed to find anything relevant.
This is the problem.
I have this code in the part of my program, doing kind of stupid sort by inserts.
I developed that in MSVS 2008 and it all worked fine, but when I tried to compile that with g++, it failed because of list::insert function below;
//...
pair<uint, double> NewElem(i, Prob.at(i));
bool inserted(false);
vector<pair<uint, double> >::const_iterator li = NewList.begin();
for ( vector<double>::const_iterator ji = BlocksMemory.begin() ; ji != BlocksMemory.end() ; ++ji)
{
if (NewElem.second <= *ji)
li += _SORT_BLOCK;
else
break;
}
for(;li != NewList.end() ; ++li)
{
if (NewElem.second > li->second)
{
NewList.insert(li, NewElem );
inserted = true;
break;
}
}
as one can see, li is const_iterator of NewList;
And NewElem has type pair with the same content type as NewList contents;
There you can see the response (unreadable):
main.cpp:447: error: no matching function for call to "std::vector<std::pair<unsigned int, double>, std::allocator<std::pair<unsigned int, double> > >::insert(__gnu_cxx::__normal_iterator<const std::pair<unsigned int, double>*, std::vector<std::pair<unsigned int, double>, std::allocator<std::pair<unsigned int, double> > > >&, std::pair<unsigned int, double>&)"
/usr/include/c++/4.4/bits/vector.tcc:106: note: candidates are: __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = std::pair<unsigned int, double>, _Alloc = std::allocator<std::pair<unsigned int, double> >]
/usr/include/c++/4.4/bits/stl_vector.h:850: note: void std::vector<_Tp, _Alloc>::insert(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, size_t, const _Tp&) [with _Tp = std::pair<unsigned int, double>, _Alloc = std::allocator<std::pair<unsigned int, double> >]
What can be the reason? And what is the possible solution?

The signature of the insert member function that you are trying to use is probably:
iterator insert( iterator, const value_type& );
But the first argument that you are passing to the function is a const_iterator, that cannot be implicitly converted to a non const iterator. That code should not have worked on VS either.
The simple solution is that if you intend to modify the container you use a non-const iterator: define li as std::vector< std::pair<uint,double> >::iterator li = NewList.begin();

Also, are you sure that you want to be inserting into a std::vector? For performance reasons, a std::list would be a better choice. Also, an insert on a list doesn't invalidate existing iterators as it does for a vector.

Related

Map Error in C++

I am using GCC 4.6 compiler and when I build my code (ns3) I get the error:
In file included from /usr/include/c++/4.4/map:60,
from ../src/internet-stack/tcp-typedefs.h:23,
from ../src/internet-stack/mp-tcp-socket-impl.cc:16:
/usr/include/c++/4.4/bits/stl_tree.h: In member function ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_II, _II) [with _InputIterator = unsigned int, _Key = unsigned int, _Val = std::pair<const unsigned int, unsigned int>, _KeyOfValue = std::_Select1st<std::pair<const unsigned int, unsigned int> >, _Compare = std::less<unsigned int>, _Alloc = std::allocator<std::pair<const unsigned int, unsigned int> >]’:
/usr/include/c++/4.4/bits/stl_map.h:553: instantiated from ‘void std::map<_Key, _Tp, _Compare, _Alloc>::insert(_InputIterator, _InputIterator) [with _InputIterator = unsigned int, _Key = unsigned int, _Tp = unsigned int, _Compare = std::less<unsigned int>, _Alloc = std::allocator<std::pair<const unsigned int, unsigned int> >]’
../src/internet-stack/mp-tcp-socket-impl.cc:1536: instantiated from here
/usr/include/c++/4.4/bits/stl_tree.h:1324: error: invalid type argument of ‘unary *’
This is because I used a map:
map<uint32_t, uint32_t> dis;
in which I inserted like this:
dis.insert(p,t);
I can't figure out a way to resolve this. Thanks for the help.
I think you are not using the insert method like you are supposed to do. I am not sure because i can't see the declaration of the arguments that you are using, but the compiler is saying that you are using the method:
void insert (InputIterator first, InputIterator last)
so the arguments may be iterators of the same container. Here the first argument designates the begin of the container to be copied and the last argument marks the end of this range (not including the last element).
These are the others options you have:
pair<iterator,bool> insert (const value_type& val);
This is the most usual and i guess you want to use this function, it inserts the element val into the map. Here val is some variable with type pair<T1,T2> where T1 and T2 are the arguments that you put in when creating the map (in your case unsigned int, unsigned int). You can use the function make_pair(first, second) of the std.
iterator insert (iterator position, const value_type& val);
The last one is like the previous but it tells to the map that the position of the new element may be near position. But this is just a hint for perfomance purpose since map is a tree with a well-defined order.
So your code might be something like dis.insert(make_pair(p,t));.
Regards.
You use libs from GCC 4.4 with GCC 4.6 - this could be the problem.
Try to pass 4.6 headers to compiler (like -I/usr/include/c++/4.6)

Trouble with std::map::emplace syntax

I am trying to emplace data into a std::map. Below is what I have tried (trimmed from the original source but definitely gives the idea):
template<typename T> class trie {
private:
std::map<typename T::value_type, std::unique_ptr<trie<T>>> children;
std::unique_ptr<trie<T>> parent;
// Later
public:
trie(const trie<T>& other, trie<T>* const parent) :
parent{parent}
{
for(auto const &it : other.children)
children.emplace(it.first, {*it.second});
}
};
The error is as follows:
trie.h: In instantiation of ‘trie<T>::trie(const trie<T>&, trie<T>*) [with T = std::basic_string<char>]’:
main.cpp:7:23: required from here
trie.h:90:3: error: no matching function for call to ‘std::map<char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > >, std::less<char>, std::allocator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > > >::emplace(const char&, <brace-enclosed initializer list>)’
children.emplace(it.first, {*it.second});
^
trie.h:90:3: note: candidate is:
In file included from /usr/include/c++/4.8.1/map:61:0,
from trie.h:4,
from main.cpp:2:
/usr/include/c++/4.8.1/bits/stl_map.h:540:2: note: 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>::emplace(_Args&& ...) [with _Args = {}; _Key = char; _Tp = std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > >; _Compare = std::less<char>; _Alloc = std::allocator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > >; 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 = std::_Rb_tree_iterator<std::pair<const char, std::unique_ptr<trie<std::basic_string<char> >, std::default_delete<trie<std::basic_string<char> > > > > >]
emplace(_Args&&... __args)
^
/usr/include/c++/4.8.1/bits/stl_map.h:540:2: note: candidate expects 0 arguments, 2 provided
So my question is:
How do I correctly initialize the map element, the goal being a deep copy of the pointed-to trie, and no needless copies/moves?
Thanks in advance!
By passing {*it.second} as the initialiser for the value, you're effectively trying to initialise a std::unique_ptr<trie<T>> with a trie<T>. I believe you're looking for this:
public:
trie(const trie<T>& other, trie<T>* const parent) :
parent{parent}
{
for(auto const &it : other.children) {
// Separate creation of unique_ptr for exception safety, thanks to #DanielFrey
std::unique_ptr<trie<T>> p(new trie<T>(*it.second));
children.emplace(it.first, std::move(p));
}
}
Note that you will also have to provide a copy constructor, because the default one is deleted, as your class has non-copyable members.
Unrelated to the question, but you should reconsider your design: you most likely have an ownership loop. If a trie<T> stores a unique_ptr to its children and these store a unique_ptr back to their parent, you'll get double deletion errors. Turn one of these (probably the pointer to parent) into a raw pointer. Raw pointers are fine for observing without participating in ownership.
You need
for(auto const &it : other.children) {
std::unique_ptr<trie<T>> element(new trie<T>(*it.second));
children.emplace(it.first, std::move(element));
}
to prevent a resource leak in case an exception is thrown from emplace. If available (C++14), you could simplify the code to
for(auto const &it : other.children) {
children.emplace(it.first, std::make_unique<trie<T>>(*it.second));
}
As a rule of thumb for all smart pointers, you always use std::make_* or you must use a separate line to create each of them.

using boost::assign with a std::set nested inside a std::map

I am trying to use boost::assign to emulate C++11 initialization of a std::map containing a std::set.
#include <set>
#include <map>
#include <stdint.h>
#include <boost/assign/list_of.hpp>
typedef std::map< uint32_t, std::set< uint32_t> > the_map_t;
the_map_t data = boost::assign::map_list_of( 1, boost::assign::list_of(10)(20)(30) )
( 2, boost::assign::list_of(12)(22)(32) )
( 3, boost::assign::list_of(13)(23)(33) )
( 4, boost::assign::list_of(14)(24)(34) );
Initialisation of std::set using boost::assign::list_of works as expected when used on its own, but when I try the above code the assignment is ambiguous at the point where the std::set's constructor is called:
map-assign.cpp:16: instantiated from here
include/c++/4.4.6/bits/stl_pair.h:101: error: call of overloaded set(const boost::assign_detail::generic_list<int>&) is ambiguous
include/c++/4.4.6/bits/stl_set.h:188: note: candidates are:
std::set<_Key, _Compare, _Alloc>::set(
const std::set<_Key, _Compare, _Alloc>&)
[with _Key = unsigned int, _Compare = std::less<unsigned int>, _Alloc = std::allocator<unsigned int>]
include/c++/4.4.6/bits/stl_set.h:145: note:
std::set<_Key, _Compare, _Alloc>::set(
const _Compare&, const _Alloc&)
[with _Key = unsigned int, _Compare = std::less<unsigned int>, _Alloc = std::allocator<unsigned int>]
How can I resolve this ambiguity error?
In this case boost::assign::map_list_of needs a hint for second template argument - <uint32_t, std::set< uint32_t> >. Therefore line
the_map_t data = boost::assign::map_list_of(...);
becomes
the_map_t data = boost::assign::map_list_of<uint32_t, std::set< uint32_t> >(...);

Is it possible to use STL copy function with map

I wonder if there is any trick to use copy with maps to copy the contents of map into an array. Because STL maps are by the combination of a key value and a mapped value an element of a map forms a key value pair. That prevents us to use standard algorithms like std::copy. For example following code gives error:
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
int
main()
{
std::map <int, double> test(4);
test[0] = 11;
test[2] = 1.23;
test[3] = 23.29;
test[1] = 12.12;
double *test_arr = (double *) malloc(4 * sizeof(double));
std::copy(test.begin(), test.end(), test_arr);
std::cout << test_arr[3] << std::endl;
return 0;
}
Error:
stl_copy_tests.cpp: In function ‘int main()’:
stl_copy_tests.cpp:9:32: error: no matching function for call to ‘std::map<int, double>::map(int)’
/usr/include/c++/4.5/bits/stl_map.h:170:7: note: candidates are: std::map<_Key, _Tp, _Compare, _Alloc>::map(const std::map<_Key, _Tp, _Compare, _Alloc>&) [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >, std::map<_Key, _Tp, _Compare, _Alloc> = std::map<int, double>]
/usr/include/c++/4.5/bits/stl_map.h:159:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::map(const _Compare&, const allocator_type&) [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >, allocator_type = std::allocator<std::pair<const int, double> >]
/usr/include/c++/4.5/bits/stl_map.h:150:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::map() [with _Key = int, _Tp = double, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, double> >]
In file included from /usr/include/c++/4.5/bits/char_traits.h:41:0,
from /usr/include/c++/4.5/ios:41,
from /usr/include/c++/4.5/ostream:40,
from /usr/include/c++/4.5/iostream:40,
from stl_copy_tests.cpp:1:
/usr/include/c++/4.5/bits/stl_algobase.h: In static member function ‘static _OI std::__copy_move<<anonymous>, <anonymous>, <template-parameter-1-3> >::__copy_m(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*, bool <anonymous> = false, bool <anonymous> = false, <template-parameter-1-3> = std::bidirectional_iterator_tag]’:
/usr/include/c++/4.5/bits/stl_algobase.h:404:70: instantiated from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
/usr/include/c++/4.5/bits/stl_algobase.h:442:39: instantiated from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false, _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
/usr/include/c++/4.5/bits/stl_algobase.h:474:18: instantiated from ‘_OI std::copy(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = double*]’
stl_copy_tests.cpp:15:47: instantiated from here
/usr/include/c++/4.5/bits/stl_algobase.h:319:6: error: cannot convert ‘std::pair<const int, double>’ to ‘double’ in assignment
Is there any easy trick/hack to overcome this problem.
Disclaimer: Not interested in solutions that iterates over map in a for loop and adds elements to the array.
You could use std::transform instead:
template <typename T, typename U>
const U &extract_second(const std::pair<T,U> &p)
{
return p.second;
}
std::transform(test.begin(), test.end(), test_arr, extract_second<int,double>);
And as #Andre points out in a comment below, if you want a slightly more verbose overhead, you can avoid having to explicitly state the template arguments via a functor:
struct extract_second
{
template <typename T, typename U>
const U operator() (const std::pair<T,U> &p) const
{
return p.second;
}
};
std::transform(test.begin(), test.end(), test_arr, extract_second());
I'm sure there's a less-verbose solution using Boost binders, but I can't remember the syntax off the top of my head.
Ewww, malloc? Anyway, if you want to copy a map, you have to remember the keys too.
int main()
{
std::map <int, double> test(4);
test[0] = 11;
test[2] = 1.23;
test[3] = 23.29;
test[1] = 12.12;
std::vector<std::pair<int, double>> test_arr(test.size());
std::copy(test.begin(), test.end(), test_arr.begin());
std::cout << test_arr[3] << std::endl;
return 0;
}
If you consider std::map an STL container, then it is a container of
std::pair<key_type, mapped_type>. (This is what its value_type is
defined to be, and it is designed so that it can be used as a
container.) If you want simply one part of it, the correct function is
std::transform, with a transformation function which maps the
value_type to either the key_type or the mapped_type. (If you make
much use of std::pair—or std::map, whose value_type is an
std::pair, you should probably have functional objects for this in
your tool kit:
struct ExtractFirst
{
template<typename Pair>
typename boost::remove_const<typename Pair::first_type>::type
operator()( Pair const& from ) const
{
return from.first;
}
};
, and the same thing for ExtractSecond.
Your target would be an arraystd::vector[please!] of std::pair<int,double> objects unless, yes, you unroll it yourself.
(You could create your own InputIterator as a proxy, or play with std::transform and a std::back_inserter, but that's just being silly. You'll make your code far more verbose than just looping through the map.)
The simplest way is to use std::transform in combination with boost::bind:
typedef std::map<int, double> map_t;
map_t mm;
// add elements to mm
// ...
// copy
typedef std::vector<double> vec_t;
vec_t vv;
vv.reserve( mm.size() );
std::transform( mm.begin(), mm.end(), std::back_inserter(vv),
boost::bind( &map_t::value_type::second, _1 ) );
If you could use C++0x (without boost):
std::transform( mm.begin(), mm.end(), back_inserter(vv),
[](map_t::value_type val) -> double { return val.second; } );
// or
std::for_each( mm.begin(), mm.end(),
[&vv](map_t::value_type val) { vv.push_back( val.second ); } );

C++ STL:map search by iterator to another map

I'm trying to jump through some hoops to organize data in a special way. I'm including a simplified piece of code that demonstrates my pain.
I can't use boost.
I'm using the latest version of g++ in cygwin.
#include <iostream>
#include <map>
using namespace std;
int main () {
map< int,int > genmap;
map< int,int >::iterator genmapit;
map< map<int,int>::iterator,int > itermap;
// insert something into genmap
genmap.insert (make_pair(1,500) );
// find and return iterator.
genmapit=genmap.find(1);
// insert the iterator/int into itermap. Dies on each of the following 3 versions of this line.
//itermap[genmapit] = 600; // crash
//itermap.insert ( pair< map<int,int>::iterator,int >(genmapit,600) ); // crash
itermap.insert ( make_pair(genmapit,600) ); // crash
return 0;
}
So as you can see, I have 1 simple map, an iterator to that map and another map that has the first argument as an iterator to the first map.
It's clear from this:
Why can't I put an iterator in map?
That I can have an iterator as the second argument. However, the way shown above provides this:
$ make
g++ -c -o main.o main.cpp
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h: In member fun
ction `bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp =
std::_Rb_tree_iterator<std::pair<const int, int> >]':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_tree.h:871: instantiate
d from `std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _All
oc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::i
nsert_unique(const _Val&) [with _Key = std::_Rb_tree_iterator<std::pair<const in
t, int> >, _Val = std::pair<const std::_Rb_tree_iterator<std::pair<const int, in
t> >, int>, _KeyOfValue = std::_Select1st<std::pair<const std::_Rb_tree_iterator
<std::pair<const int, int> >, int> >, _Compare = std::less<std::_Rb_tree_iterato
r<std::pair<const int, int> > >, _Alloc = std::allocator<std::pair<const std::_R
b_tree_iterator<std::pair<const int, int> >, int> >]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_map.h:360: instantiated
from `std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_
Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, bool> std::
map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [wit
h _Key = std::_Rb_tree_iterator<std::pair<const int, int> >, _Tp = int, _Compare
= std::less<std::_Rb_tree_iterator<std::pair<const int, int> > >, _Alloc = std:
:allocator<std::pair<const std::_Rb_tree_iterator<std::pair<const int, int> >, i
nt> >]'
main.cpp:23: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h:227: error: no
match for 'operator<' in '__x < __y'
make: *** [main.o] Error 1
"instantiated from here" tells me nothing and a web search gives me no info on this.
Does STL:map simply not allow for this? I can recode my app to work around this but it will be very inefficient and I would like to get this working. Is there another kind of pointer I can make for a map element I could use?
Thanks for your time.
You can't do this because std::map iterators are not random access iterators so aren't comparable with <.
Instead, you could use pointers to the value_type in the first map as a map key.
You have to learn to read the error messages. In particular look at the message that comes after the long-winded description where the error happened:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h:227: error: no
match for 'operator<' in '__x < __y'
Map iterators are not comparable with less-than operator which the map uses by default.
I suppose you can provide a comparison function that compares the pairs pointed to by the iterator, since the iterators themselves cannot be easily compared in a meaningful way.
struct CompareIterator
{
template <class FirstIter, class SecondIter>
bool operator()(FirstIter lhv, SecondIter rhv) const
{
return *lhv < *rhv;
}
};
//usage with map:
map< map<int,int>::iterator,int, CompareIterator > itermap;
std::pair defines operator<. I also used two iterator types, since it might be possible the types are different (iterator and const_iterator)
map<Key, Value>
The map iterator as key element into another map is not possible because map expects operator < to be defined by default to the key. If the Key (in this case map iterator) is not defined then you need to pass a functor as a predicate function that provides the comparison of Key (map iterator).