The IMHO valid C++ code in the sample program tt.cc (see below) fails to compile. I've tried using different STL containers, but the result was (more or less) the same. I've tried to compile this code with three different versions of gcc (3.2.1, 3.2.2, and 3.4.1), and all three fail. Furthermore, I've tried to compile it with the Intel C++ compiler (v8.0) which accepts the code. $ g++ -v Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs Configured with: ../configure --prefix=/usr --mandir=/usr/share/man -- infodir=/usr/share/info --enable-shared --enable-threads=posix --disable- checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux Thread model: posix gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5) $ g++ -save-temps tt.cc /usr/include/c++/3.2.2/bits/stl_alloc.h: In instantiation of `std::allocator<X* const>': tt.cc:9: instantiated from here /usr/include/c++/3.2.2/bits/stl_alloc.h:674: `const _Tp* std::allocator<_Alloc>::address(const _Tp&) const [with _Tp = X* const]' and `_Tp* std::allocator<_Alloc>::address(_Tp&) const [with _Tp = X* const]' cannot be overloaded /usr/include/c++/3.2.2/bits/stl_construct.h: In function `void std::_Construct(_T1*, const _T2&) [with _T1 = X* const, _T2 = X*]': /usr/include/c++/3.2.2/bits/stl_list.h:328: instantiated from `std::_List_node<_Tp>* std::list<_Tp, _Alloc>::_M_create_node(const _Tp&) [with _Tp = X* const, _Alloc = std::allocator<X* const>]' /usr/include/c++/3.2.2/bits/stl_list.h:430: instantiated from `std::_List_iterator<_Tp, _Tp&, _Tp*> std::list<_Tp, _Alloc>::insert (std::_List_iterator<_Tp, _Tp&, _Tp*>, const _Tp&) [with _Tp = X* const, _Alloc = std::allocator<X* const>]' /usr/include/c++/3.2.2/bits/stl_list.h:479: instantiated from `void std::list<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = X* const, _Alloc = std::allocator<X* const>]' tt.cc:10: instantiated from here /usr/include/c++/3.2.2/bits/stl_construct.h:78: static_cast from type `X* const*' to type `void*' casts away constness $ cat tt.cc #include <list> struct X { }; int main() { std::list<X* const> li; li.push_back(new X()); }
Created attachment 6880 [details] Precompiler output tt.ii for the source file tt.cc
Confirmed. In a sense I believe that what you try to do is nonsensical: 'X*const' means that the pointer won't change, not that the object pointed to won't change. Now, how the std::list stores its pointers to the object shouldn't be of much concern to you, in particular std::list should be able to copy around its internal data structures, even if you don't see it. But if you mark the pointer as const, std::list can't in many places just replace one pointer by another because it changed the layout of the data it stores. That being said, icc shows that there are apparently ways to make even nonsensical code compile :-) Not sure, though, if this request will receive high priority... libstdc++ people: is there anything in the standard about this case? W.
Interesting... By the way, the issue is just: #include <memory> std::allocator<int* const> a;
... indeed, the error: /usr/include/c++/3.2.2/bits/stl_alloc.h:674: `const _Tp* std::allocator<_Alloc>::address(const _Tp&) const [with _Tp = X* const]' and `_Tp* std::allocator<_Alloc>::address(_Tp&) const [with _Tp = X* const]' cannot be overloaded definitely makes sense for _Tp == X* const! Gaby?
Or, in other terms: template <typename T> struct A { void d(T& __x) { } void d(const T& __x) { } }; A<int* const> a; paolo:~/Work> g++ 16875_red.cc 16875_red.cc: In instantiation of `A<int* const>': 16875_red.cc:13: instantiated from here 16875_red.cc:10: error: `void A<T>::d(const T&) [with T = int* const]' and `void A<T>::d(T&) [with T = int* const]' cannot be overloaded Now, I have *no* idea how Icc can avoid instantiating the allocator or whatelse, but of course also Icc doesn't compile the above.
Invalid as 20.4.1 for allocator: pointer address(reference x) const; const_pointer address(const_reference x) const;
Subject: Re: Fails to compile: STL container of const pointer to X "pcarlini at suse dot de" <gcc-bugzilla@gcc.gnu.org> writes: | ... indeed, the error: | | /usr/include/c++/3.2.2/bits/stl_alloc.h:674: `const _Tp* | std::allocator<_Alloc>::address(const _Tp&) const [with _Tp = X* const]' and | `_Tp* std::allocator<_Alloc>::address(_Tp&) const [with _Tp = X* const]' | cannot be overloaded | | definitely makes sense for _Tp == X* const! | | Gaby? The code shown in the report does not make sense: You can't put a const T in a standard sequence. People have figured out that there is another issue with allocator. So the PR is doubly invalid :-) -- Gaby
*** Bug 17866 has been marked as a duplicate of this bug. ***
I've reopened this PR after looking at #16875 (which I can't re-open, although I've cross-posted this note there). The basic argument to reject that bug was that putting consts in a standard collection is non-sensical, because the collections re-organize themselves and you can't do that with a const element type. This seems shortsighted, as my application shows (the test case I submitted was simplified from the actual use). In my application, I have a number of data values (the number is statically known) that I need to put into a data structure and subsequently do various kinds of searches on them. The searchers are not to be permitted to change the values once they are in the structure. Using "int" as the element and "vector" as the collection (mine is more complicated), the code looks something like: vector<const int> v; #define count = 5 v.reserve(count); void init() { for (int i = 0; i < count; ++i) {int j; j << cin; v.push_back(j);}} // push_back works because it constructs, not copies void use() { for_each(v.begin(), v.end(), something()); } That is, I want to be able to use the whole algorithm and collection machinery without re-inventing the wheel, on a standard collection and that collection's contents that will be immutable once it is built. This seems a reasonable need to me; do you differ and still think it is non-sensical? Ivan
For the record, the following was posted on comp.std.c++: Try: std::allocator<const int> a; This fails on gcc and is permitted in icc and the other EDG derivatives. While allocating const objects may seem non-sensical, that's what you do when you have a standard collection of const value type. And you have (or want to have) such a collection of const objects whenever you have a bunch of data that you want to put in a standard collection to use standard algorithms on (say for searching) but which will be (or should be) immutable once the collection is constructed. g++ complains about the definition of the "address" function in std::allocator, and the g++ folks say (in response to the PR, bug #16875; see also #17866): "Invalid as 20.4.1 for allocator: pointer address(reference x) const; const_pointer address(const_reference x) const;" However, the utility of the application is obvious and the utility of the restriction is not, so I propose that the library specification be changed to support allocators (and by implication collections) of const element type. Apparently icc uses a specialization of allocator to merge the declarations of "address" when the argument type is const, which is a pretty trivial fix. No existing code would be invalidated by the change. Sincerely, Ivan Godard
(In reply to comment #12) ... > Apparently icc uses a specialization of allocator to merge the declarations of > "address" when the argument type is const, which is a pretty trivial fix. No > existing code would be invalidated by the change. ... After I posted this bug, with the notion that ICC did compile my code example with a container of const elements, I've been looking at the ICC STL header files, and (no offense to Intel, etc.) they seem to be based on STLport and look rather ancient. For instance, under the hood, this STL implementations uses void pointers throughout. This probably explains why my original example did compile using ICC. So, in short, the changes to be made to the GCC STL implementation will probably not be trivial, unless one would like to go back to the type unsafe void pointer era. Furthermore, as was noted in comment #12, this is a more fundamental issue. The current C++ standard is pretty clear about the allocator rule (of which I was unaware at the time of submitting the bug report), however the reason behind this rule is very unclear and appears needlessly restrictive to me. Does anyone in the C++ standardization committee have something to say about this? Marcel Loose.