Topic: allocators of const types


Author: igodardA@TpacbellDO.Tnet ("Ivan Godard")
Date: Thu, 7 Oct 2004 04:02:27 GMT
Raw View
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

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Thu, 7 Oct 2004 15:43:29 GMT
Raw View
igodardA@TpacbellDO.Tnet ("Ivan Godard") wrote in message
news:<zK19d.25057$QJ3.12273@newssvr21.news.prodigy.com>...

> Try:
>     std::allocator<const int> a;

> This fails on gcc and is permitted in icc and the other EDG derivatives.

It's undefined behavior, I think.

> While allocating const objects may seem non-sensical, that's what you
> do when you have a standard collection of const value type.

You can't have a standard collection of const value types.  The standard
requires that all elements of a collection be assignable, at all times.
Const types aren't assignable.

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

Then you make the collection const.  The way the STL is designed, the
const-ness of a container percolates down to the objects it contains.
(This seems more than reasonable to me, and is, of course, the way
built-in arrays work as well.)

I do this a lot.  Of course, it only works on systems where the template
constructors work; otherwise, you have a lot of difficulty initializing
the collection.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: igodardA@TpacbellDO.Tnet ("Ivan Godard")
Date: Thu, 7 Oct 2004 17:36:19 GMT
Raw View
""Ivan Godard"" <igodardA@TpacbellDO.Tnet> wrote in message
news:zK19d.25057$QJ3.12273@newssvr21.news.prodigy.com...
> 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.

After posting the original on this thread I became aware that this issue had
already been addressed by the committee  as DR274 (see
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html). Therein it
says in part:

"Two resolutions were originally proposed: one that partially specialized
std::allocator for const types, and one that said an allocator's value type
may not be const. The LWG chose the second. The first wouldn't be
appropriate, because allocators are intended for use by containers, and
const value types don't work in containers. Encouraging the use of
allocators with const value types would only lead to unsafe code."

With due respect, I think that the LWG should re-examine this DR and reach a
different conclusion.

1) Allocators have use outside the standard containers, both to manage
storage with unusual behavior (the ARM gives an extensive example) and for
use with home-grown container-like classes that are not actually
standard-conforming containers (the Boost dynamic-bitset library is an
example).

2) Containers of const value types are meaningful and would be useful if
only they were permitted. True, some operations would fail for a const type.
However, most (all?) container types can be used in ways that involve only
construction and not copy of the elements and so it would be possible to
construct a container full of const objects. Once built, such a container
could be used for all the non-mutating operations (such as searches) and
standard algorithms. For example:

    int count;
    vector<const int>    vec;
    cin >> count;
    vec.reserve(count);
    for (; count != 0; --count) { int j; cin>>j; vec.push_back(j); }
        //    vec now populated, use it but don't change the data it
contains.
    for_each(vec.begin(), vec.end(), something());

This is a simplification of my own application that prompted this posting,
except that the data is not int and the standard collection I use is not
vector.

Because collections of const types are illegal, I am left with two choices:
1) Abandon use of standard, debugged and portable collections and roll my
own.
2) Keep on using the standard collections, but with a non-const type, and
thereby weaken the immutability constraint that I want my data to require.

Neither choice seems attractive, so I propose that container types should
gave specializations that permit them to be used with const types. The
effort seems minor, the benefits clear, and no existing code is disturbed.

Ivan



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ark@acm.org ("Andrew Koenig")
Date: Thu, 7 Oct 2004 18:10:14 GMT
Raw View
""Ivan Godard"" <igodardA@TpacbellDO.Tnet> wrote in message
news:zK19d.25057$QJ3.12273@newssvr21.news.prodigy.com...

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

If you look at subclause 23.1, paragraph 3 of the C++ standard, you will see
that types stored in standard containers are required to be
copy-constructable and assignable.  Const types are not assignable, so C++
implementations are not required to support standard containers of const
types.

I can understand why you might like to have such a container, but the fact
is that the standard doesn't require implementations to support them.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: falk.tannhauser@crf.canon.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Thu, 7 Oct 2004 20:56:55 GMT
Raw View
X-Replace-Address:yes
Ivan Godard wrote:

> Because collections of const types are illegal, I am left with two choices:
> 1) Abandon use of standard, debugged and portable collections and roll my
> own.
> 2) Keep on using the standard collections, but with a non-const type, and
> thereby weaken the immutability constraint that I want my data to require.

How about
3) Keep on using the standard collections with a non-const type, and only
access them through a const-qualified access path once they are initialised.
This restriction could be enforced through encapsulation.

One could imagine a template for doing this:
___________________________________________________________________________________________________
#include <memory>

template<template<typename V, typename A> class Container,
         typename ValueType,
         typename Alloc = std::allocator<ValueType> >
class const_container_adapter
{
public:
  typedef ValueType const value_type;
  typedef Alloc allocator_type;
  typedef Container<ValueType, Alloc> container_type;
  typedef typename container_type::const_iterator const_iterator;
  typedef typename container_type::const_reverse_iterator const_reverse_iterator;
  typedef typename container_type::const_pointer const_pointer;
  typedef typename container_type::const_reference const_reference;
  typedef typename container_type::size_type size_type;
  typedef typename container_type::difference_type difference_type;

  void push_back(ValueType const& v) { cont.push_back(v); }
  void push_front(ValueType const& v) { cont.push_front(v); }

  explicit const_container_adapter(Alloc const& a = Alloc()) : cont(a) {}

  template <class InputIterator>
  const_container_adapter(InputIterator first, InputIterator last, Alloc const& a = Alloc())
    : cont(first, last, a) {}

  const_iterator begin() const { return cont.begin(); }
  const_iterator end() const { return cont.end(); }
  const_reverse_iterator rbegin() const { return cont.rbegin(); }
  const_reverse_iterator rend() const { return cont.rend(); }
  size_type size() const { return cont.size(); }
  ValueType const& operator[](size_type i) const { return cont[i]; }
  ValueType const& at(size_type i) const { return cont.at(i); }
  //... Add other constructors and member functions as you want

private:
  container_type cont;
};

////////////////////////////////////////////////// Test ///////////////////////////////////////////
#include <vector>
#include <list>
#include <iostream>
#include <ostream>
#include <iterator>

int main()
{
  const_container_adapter<std::vector, int> vec_int;
  vec_int.push_back(42);
  vec_int.push_back(666);
  vec_int.push_back(4711);

  const_container_adapter<std::list, double> list_double(vec_int.rbegin(), vec_int.rend());

  std::copy(list_double.begin(), list_double.end(), std::ostream_iterator<double>(std::cout, " "));
  std::cout << '\n';
  return 0;
}
___________________________________________________________________________________________________

Falk

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]