gcc workaround while using shared_ptr to insert in std::set - c++

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

Related

How to use std::reference_wrapper in std::map for both key and value? [duplicate]

I have a bunch of objects in a class hierarchy and would like to make a std::map using references to those objects as the keys in the map. Its seems like std::reference_wrapper would be exactly what is needed for this, but I can't seem to make it work. What I've tried so far:
class Object { // base class of my hierarchy
// most details unimportant
public
virtual bool operator< (const Object &) const; // comparison operator
};
std::map<std::reference_wrapper<const Object>, int> table;
auto it = table.find(object);
table[object] = 42;
table[object]++
However, I always get somewhat obscure errors from the compiler:
/usr/include/c++/4.5.3/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::reference_wrapper<const Object>]’:
/usr/include/c++/4.5.3/bits/stl_tree.h:1522:38: instantiated from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) [with _Key = std::reference_wrapper<const Object>, _Val = std::pair<const std::reference_wrapper<const Object>, int>, _KeyOfValue = std::_Select1st<std::pair<const std::reference_wrapper<const Object>, int> >, _Compare = std::less<std::reference_wrapper<const Object> >, _Alloc = std::allocator<std::pair<const std::reference_wrapper<const Object>, int> >, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::reference_wrapper<const Object>, int> >]’
/usr/include/c++/4.5.3/bits/stl_map.h:697:29: instantiated from ‘std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&)[with _Key = std::reference_wrapper<const Object>, _Tp = int, _Compare = std::less<std::reference_wrapper<const Object> >, _Alloc = std::allocator<std::pair<const std::reference_wrapper<const Object>, int> >, std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::reference_wrapper<const Object>, int> >, key_type = std::reference_wrapper<const Object>]’
testfile.cpp:39:31: instantiated from here
/include/c++/4.5.3/bits/stl_function.h:230:22: error: no match for ‘operator<’ in ‘__x < __y’
The error seems to be saying it can't compare two std::reference_wrapper<const Object> objects, but it seems like it should be possible -- std::reference_wrapper has a conversion operator that can implicitly convert it to a T& (const Object & here), and Object has a operator <, so why doesn't it work?
Should it work and this is merely a bug in g++? Or is something else going on?
By default std::map uses std::less<std::reference_wrapper<const Object>> as Compare, but std::reference_wrapper<T> doesn't forward operator<() to the underlying type T.
The simplest and concisest option to solve your problem is to define std::less<const Object> (or std::greater<const Object>) in the map definition like this:
std::map<std::reference_wrapper<const Object>, int, std::less<const Object>> table;
It will work correctly and as expected due to implicit conversion of std::reference_wrapper to T& and implicit constructor of std::reference_wrapper.
Example.
It seems that it would work if you made the comparison operator a free function (that perhaps calls a virtual member function).
If it is a member function, a < b really means a.operator<(b); and implicit conversions are not considered for the left-side argument.
On Visual Studio 11 Beta, I get the same problem.
Using the free version which calls the < operator solves the problem.
#include<map>
#include<iostream>
using namespace::std;
class Object {
int _n1;
public:
Object(int n = 0):_n1(n){};
bool operator < (const Object& rhs) const {return this->_n1 < rhs._n1;}
friend ostream &operator << (ostream &stream, const Object& o) { stream << o._n1 << " "; return stream;}
};
struct ObjectLess{
bool operator()(const Object& lhs, const Object& rhs) const
{
return lhs<rhs;
}
};
int main(int argc, char* argv[])
{
//This does not compile
//std::map<std::reference_wrapper<const Object>, string> table;
//Using the free function works
std::map<std::reference_wrapper<const Object>, string, ObjectLess> table;
Object a(1);
Object b(2);
Object c(3);
table[a]="One";
table[c]="Three";
table[b]="Two";
for(auto y: table){
cout << y.first << " " << y.second.c_str() << std::endl;
}
return 0;
}

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);
}
}

C++ Use of deleted function error

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.

I can`t solve a passing constant error with my actual knowledge [duplicate]

This question already has an answer here:
std::map access operator deprecated? no operator [] matches these operands
(1 answer)
Closed 8 years ago.
I made a specialization for a bidirectional map when the key type and value type are the same.
Also I made 2 definitions for the operator[] ,one to return constant and one to return non constant. But this did not solve my problem.I get an error that i`m passing constant as *this...
Here it is the specialization:
template<class A>
class BidirectionalMap<A,A>
{
public:
void insert(A a,A b)
{
m1.insert(std::pair<A,A> (a,b));
m1.insert(std::pair<A,A> (b,a));
}
BidirectionalMap& operator =(BidirectionalMap &a)
{
m1=a.m1;
return *this;
}
const A& at(const A& a) const
{
return m1.at(a);
}
int size() const
{
return m1.size();
}
int count(const A& a) const
{
return m1.count(a);
}
A& operator[](const A& a)
{
return m1[a];
}
const A& operator[](const A& a) const
{
return m1[a];////here pinpoints me that error: passing 'const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >' as 'this' argument of 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = int; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]' discards qualifiers [-fpermissive]
}
private:
std::map<A,A> m1;
};
And the error shows in this context:
BidirectionalMap<int, int> f;
f.insert(3, 18);
f.insert(8, 2);
f.insert(7, 5);
f.insert(9, 1);
const BidirectionalMap<int, int> cf = f;
if( f.at(5) == 7 &&
f.count(12) == 0 &&
f.at(8) == 2)
{
yourMark = cf[18] + cf[9];//here is the error
}
Any idea?
operator[] is typically not const in std::map
See http://www.cplusplus.com/reference/map/map/operator%5B%5D/
The reason is that operator[] allows to insert if the element is not present.

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;
}