Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map of string to boost::thread_specific_ptr

Why does this fail to compile g++4.6 and g++4.7? I am trying to get a mapping of string to thread specific storage. I had something like this working in boost 1.48 I believe. Actually, it is not related to the version of boost, but the flag -std=c++0x. If that is not present it compiles. So, looking for interpretation of error and how to work around it.

Thanks

#include <map>
#include <boost/thread/tss.hpp>
#include <boost/shared_ptr.hpp>

int main(int argc, char** argv) {
  typedef boost::thread_specific_ptr< int > Tss_int_ptr;
  typedef std::map< std::string, Tss_int_ptr > Tss_int_map_t;
  Tss_int_map_t tmap;
  return 0;
}

The error message follows.

g++-4.7 -g -std=c++0x -I"/home/someone/open_source/admin/install/boost_1_52_0/include" -c  ~/tmp/fail.cpp
In file included from /usr/include/c++/4.7/bits/stl_algobase.h:65:0,
             from /usr/include/c++/4.7/bits/stl_tree.h:63,
             from /usr/include/c++/4.7/map:60,
             from /home/someone/tmp/fail.cpp:1:
/usr/include/c++/4.7/bits/stl_pair.h: In instantiation of ‘struct std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> >’:
/usr/include/c++/4.7/bits/stl_tree.h:133:12:   required from ‘struct std::_Rb_tree_node<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >’
/usr/include/c++/4.7/bits/stl_tree.h:1082:4:   required from ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_erase(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type) [with _Key = std::basic_string<char>; _Val = std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> >; _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >*]’
/usr/include/c++/4.7/bits/stl_tree.h:646:9:   required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::~_Rb_tree() [with _Key = std::basic_string<char>; _Val = std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> >; _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> > >]’
/usr/include/c++/4.7/bits/stl_map.h:90:11:   required from here
/usr/include/c++/4.7/bits/stl_pair.h:119:17: error: ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const std::basic_string<char>; _T2 = boost::thread_specific_ptr<int>; std::pair<_T1, _T2> = std::pair<const std::basic_string<char>, boost::thread_specific_ptr<int> >]’ declared to take const reference, but implicit declaration would take non-const
like image 533
user1338952 Avatar asked Jul 23 '26 17:07

user1338952


1 Answers

thread_specific_ptr declares these members, in order to make the class non-copyable (note the non-const parameters):

private:
    thread_specific_ptr(thread_specific_ptr&);
    thread_specific_ptr& operator=(thread_specific_ptr&);

In C++03 std::pair does not have a copy constructor declared, so one is implicitly generated if needed by the program. A std::pair<X, thread_specific_ptr> is not copyable, because one of its members is not copyable, so if the implicit copy constructor was used it would be an error.

In C++11 std::pair has a copy constructor, which is explicitly defaulted. It has the signature:

pair(const pair&) = default;

The compiler error is telling you that the implicitly-generated copy constructor would have this signature, because the thread_specific_ptr copy constructor signature takes a non-const reference:

pair(pair&) = default;

Because the defaulted constructor does not have the same signature as what would have be implicitly declared, the copy constructor is ill-formed.

So in both cases the pair<X, thread_specific_ptr> is not copyable, but in C++11 the error is noticed sooner, even though you don't try to copy the object.

If boost::thread_specific_ptr used the normal C++11 idiom for making a class non-copyable the code would work:

thread_specific_ptr(const thread_specific_ptr&) = delete;
thread_specific_ptr& operator=(const thread_specific_ptr&) = delete;

So I would report this as a bug to Boost. In C++11 mode the copy operations should be deleted.

As a workaround you can wrap the type in your own type with deleted copy operations, then use that instead:

template<typename T>
struct TSS : boost::thread_specific_ptr<T>
{
  TSS() = default;
  TSS(void (*f)(T*)) : boost::thread_specific_ptr<T>(f) { }
  TSS(const TSS&) = delete;
  TSS& operator=(const TSS&) = delete;
};

Now you can use this and your code will compile:

typedef TSS< int > Tss_int_ptr;
like image 66
Jonathan Wakely Avatar answered Jul 26 '26 06:07

Jonathan Wakely