TITLE: std::containter deletion problem with "const T" (Newsgroups: comp.std.c++, 14 Sep 99) KOENIG: Andrew Koenig >The question is how much work the author of this class has to do >in order to enable a Container to work properly. NARAN: Siemel B. Naran Even within the current rules, a std::container is improper. Consider std::container v(3,0); which creates a container of 3 elements, each initialized to '0'. I. To find space for 3 elements, the container calls the default allocator's allocate function. In template form, it is T * allocator::allocate(size_type N) { return static_cast(std::malloc(N*sizeof(T))); } For T=="int const", it is int const * allocator::allocate(size_type N) { return static_cast(std::malloc(N*sizeof(int const))); } As static_cast cannot be used to add or remove const qualifiers, the cast is illegal. II. To construct each element, the container calls the default allocator's construct function. In template form, it is void allocator::construct(T * place, const T& obj) { new (place) T(obj); } For T=="int const", it is void allocator::construct(int const * place, const const int& obj) { new (place) (const int)(obj); } The call to placement new is illegal as it tries to modify a read-only location. The compiler must ignore two consts in a row in implicit template instantiation, so the declaration is legal. Incidentally, this means that the following two functions are the same typename allocator:: pointer tor::address( reference); typename allocator::const_pointer allocator::address(const_reference); Thus the rule that the compiler must ignore two consts in a row could be an error in the standard. If it is an error, then the declaration is illegal too. (BTW, there was an issue that in expressions like std::bind2nd(std::mem_fun(&X::show),std::cout) we end up with a reference to a reference. For example, because the function show is X::show(std::ostream&), the constructor of std::binder2nd is std::binder2nd::binder2nd(const Oper&, const std::ostream& &); Forcing a reference to a reference to be a reference may cause problems as above.) III. To destroy the 3 elements, the container calls the default allocator's destroy function. In template form, it is void allocator::destroy(T * obj) { obj->~T(); } For T=="int const", it is void allocator::destroy(int const * obj) { obj->~T(); } It seems to me that this should be illegal, but by the current rules of C++, it is legal. IV. To deallocate the 3 elements, the container calls the default allocator's deallocate function. In template form, it is void allocator::deallocate(T * array) { std::free(array); } For T=="int const", it is void allocator::deallocate(int const * array) {std::free(array);} This is an error because the single argument of std::free is a "void *".