Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does stack<const string> not compile in g++? [duplicate]

I encountered this problem maintaining a port for a large (relative to the size of our team) project, but it was simple to create a small example. stackoverflow.cpp:

#include<iostream>
#include<string>
#include<stack>

using namespace std;


int main (int argc, char *argv[]) {
  stack<const string> strstack;
  string str("Hello, world");
  strstack.push(str);
  cout << strstack.top() << endl;
  return 0;
}

Looks correct, right? MSVS thinks so too. However:

g++ stackoverflow.cpp
In file included from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34:0,
                 from /usr/include/c++/4.7/bits/allocator.h:48,
                 from /usr/include/c++/4.7/string:43,
                 from /usr/include/c++/4.7/bits/locale_classes.h:42,
                 from /usr/include/c++/4.7/bits/ios_base.h:43,
                 from /usr/include/c++/4.7/ios:43,
                 from /usr/include/c++/4.7/ostream:40,
                 from /usr/include/c++/4.7/iostream:40,
                 from stackoverflow.cpp:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘class __gnu_cxx::new_allocator<const std::basic_string<char> >’:
/usr/include/c++/4.7/bits/allocator.h:89:11:   required from ‘class std::allocator<const std::basic_string<char> >’
/usr/include/c++/4.7/bits/stl_deque.h:489:61:   required from ‘class std::_Deque_base<const std::basic_string<char>, std::allocator<const std::basic_string<char> > >’
/usr/include/c++/4.7/bits/stl_deque.h:728:11:   required from ‘class std::deque<const std::basic_string<char>, std::allocator<const std::basic_string<char> > >’
/usr/include/c++/4.7/bits/stl_stack.h:98:46:   required from ‘class std::stack<const std::basic_string<char> >’
stackoverflow.cpp:9:23:   required from here
/usr/include/c++/4.7/ext/new_allocator.h:83:7: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const std::basic_string<char>; __gnu_cxx::new_allocator<_Tp>::const_pointer = const std::basic_string<char>*; __gnu_cxx::new_allocator<_Tp>::const_reference = const std::basic_string<char>&]’ cannot be overloaded
/usr/include/c++/4.7/ext/new_allocator.h:79:7: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const std::basic_string<char>; __gnu_cxx::new_allocator<_Tp>::pointer = const std::basic_string<char>*; __gnu_cxx::new_allocator<_Tp>::reference = const std::basic_string<char>&]’
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::deallocate(__gnu_cxx::new_allocator<_Tp>::pointer, __gnu_cxx::new_allocator<_Tp>::size_type) [with _Tp = const std::basic_string<char>; __gnu_cxx::new_allocator<_Tp>::pointer = const std::basic_string<char>*; __gnu_cxx::new_allocator<_Tp>::size_type = long unsigned int]’:
/usr/include/c++/4.7/bits/stl_deque.h:540:2:   required from ‘void std::_Deque_base<_Tp, _Alloc>::_M_deallocate_node(_Tp*) [with _Tp = const std::basic_string<char>; _Alloc = std::allocator<const std::basic_string<char> >]’
/usr/include/c++/4.7/bits/stl_deque.h:643:2:   required from ‘void std::_Deque_base<_Tp, _Alloc>::_M_destroy_nodes(_Tp**, _Tp**) [with _Tp = const std::basic_string<char>; _Alloc = std::allocator<const std::basic_string<char> >]’
/usr/include/c++/4.7/bits/stl_deque.h:566:4:   required from ‘std::_Deque_base<_Tp, _Alloc>::~_Deque_base() [with _Tp = const std::basic_string<char>; _Alloc = std::allocator<const std::basic_string<char> >]’
/usr/include/c++/4.7/bits/stl_deque.h:781:15:   required from ‘std::deque<_Tp, _Alloc>::deque() [with _Tp = const std::basic_string<char>; _Alloc = std::allocator<const std::basic_string<char> >]’
stackoverflow.cpp:9:23:   required from here
/usr/include/c++/4.7/ext/new_allocator.h:100:9: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
In file included from /usr/include/c++/4.7/ext/new_allocator.h:34:0,
                 from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34,
                 from /usr/include/c++/4.7/bits/allocator.h:48,
                 from /usr/include/c++/4.7/string:43,
                 from /usr/include/c++/4.7/bits/locale_classes.h:42,
                 from /usr/include/c++/4.7/bits/ios_base.h:43,
                 from /usr/include/c++/4.7/ios:43,
                 from /usr/include/c++/4.7/ostream:40,
                 from /usr/include/c++/4.7/iostream:40,
                 from stackoverflow.cpp:1:
/usr/include/c++/4.7/new:97:6: error:   initializing argument 1 of ‘void operator delete(void*)’ [-fpermissive]
In file included from /usr/include/c++/4.7/deque:63:0,
                 from /usr/include/c++/4.7/stack:61,
                 from stackoverflow.cpp:3:
/usr/include/c++/4.7/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, const _T2&) [with _T1 = const std::basic_string<char>; _T2 = std::basic_string<char>]’:
/usr/include/c++/4.7/bits/stl_uninitialized.h:77:3:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>; _ForwardIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>; bool _TrivialValueTypes = false]’
/usr/include/c++/4.7/bits/stl_uninitialized.h:119:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>; _ForwardIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>]’
/usr/include/c++/4.7/bits/stl_uninitialized.h:260:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>; _ForwardIterator = std::_Deque_iterator<const std::basic_string<char>, const std::basic_string<char>&, const std::basic_string<char>*>; _Tp = const std::basic_string<char>]’
/usr/include/c++/4.7/bits/stl_deque.h:841:9:   required from ‘std::deque<_Tp, _Alloc>::deque(const std::deque<_Tp, _Alloc>&) [with _Tp = const std::basic_string<char>; _Alloc = std::allocator<const std::basic_string<char> >; std::deque<_Tp, _Alloc> = std::deque<const std::basic_string<char>, std::allocator<const std::basic_string<char> > >]’
/usr/include/c++/4.7/bits/stl_stack.h:130:14:   required from ‘std::stack<_Tp, _Sequence>::stack(const _Sequence&) [with _Tp = const std::basic_string<char>; _Sequence = std::deque<const std::basic_string<char>, std::allocator<const std::basic_string<char> > >]’
stackoverflow.cpp:9:23:   required from here
/usr/include/c++/4.7/bits/stl_construct.h:85:7: error: invalid static_cast from type ‘const std::basic_string<char>*’ to type ‘void*’

With stack<string> strstack; it's all clean. Is this a g++ bug? Is there a workaround so that we won't have to drop the const until the bug is fixed?

like image 733
01d55 Avatar asked Nov 03 '12 22:11

01d55


2 Answers

The members of a standard container have to be copy assignable or movable (C++11). If the type is const it fails the requirements.

like image 95
Bo Persson Avatar answered Nov 13 '22 18:11

Bo Persson


It is possible for the container to hold pointers (or preferably, smart pointers) to constants. This maintains the desired const semantics, although perhaps the syntax is a bit more clunky.

For example:

stack<shared_ptr<string const>> s;
s.push(make_shared<string>("foo"));
cout << *s.top() << endl;

For more info see this question.

like image 30
Kevin Avatar answered Nov 13 '22 17:11

Kevin