Topic: Clarification of what container::max_size() means.


Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Sat, 26 Sep 2009 15:35:20 CST
Raw View
Microsoft will not fix what I consider a bug in VC++ STL implementation
until there is clarification in the standard of what container::max_size()
actually means, or more specifically how it relates to
allocator::max_size().

The standard states that allocator::max_size() is the largest value that can
be passed to allocator::allocate whilst container::max_size() is largest
possible size() of the container.  VC++ STL assumes that
container::max_size() is equivalent to allocator::max_size() which I think
is incorrect.  g++ assumes that container::max_size() is different to
allocator::max_size() which I think is correct.  When writing a custom
allocator it is possible that the allocator might return 1 for
allocator::max_size() even though you can allocate more than one element via
multiple calls to allocator::allocate (consider a non-contiguous chunk/pool
allocator).

Could we have clarification in the standard to satisfy Microsoft?

The VC++ bug is
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=490955

/Leigh


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Bo Persson" <bop@gmb.dk>
Date: Sun, 27 Sep 2009 09:24:09 CST
Raw View
Leigh Johnston wrote:
> Microsoft will not fix what I consider a bug in VC++ STL
> implementation until there is clarification in the standard of what
> container::max_size() actually means, or more specifically how it
> relates to allocator::max_size().
>
> The standard states that allocator::max_size() is the largest value
> that can be passed to allocator::allocate whilst
> container::max_size() is largest possible size() of the container.
> VC++ STL assumes that container::max_size() is equivalent to
> allocator::max_size() which I think is incorrect.  g++ assumes that
> container::max_size() is different to allocator::max_size() which I
> think is correct.  When writing a custom allocator it is possible
> that the allocator might return 1 for allocator::max_size() even
> though you can allocate more than one element via multiple calls to
> allocator::allocate (consider a non-contiguous chunk/pool
> allocator).
> Could we have clarification in the standard to satisfy Microsoft?
>
> The VC++ bug is
> https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=490955
>
> /Leigh

The committee has already considered another request to improve the
wording, but declined.

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#197


I believe the intent was to have an (ball park) upper limit to the
allocation size. If you try to allocate more than
allocator::max_size(), you are certain that this will fail. This
doen't mean that max_size() - 1 will succeed.

For example, the std::allocator<T> supplied by Microsoft effectively
returns numeric_limits<size_t>::max() / sizeof(T), which is a gross
over estimation, considering that the OS reserves half the address
space for itself.

That's about how precise the function is.


Bo Persson



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Mon, 28 Sep 2009 03:33:39 CST
Raw View
Yes but my point is that container::max_size() is different to
allocator::max_size().  A custom allocator can return something more
useful than what most std::allocator implementations return.
Microsoft are treating container::max_size() as equivalent to
allocator::max_size() which is incorrect as allocator::max_size()
relates to a *particular* allocation request, not the sum of *all*
allocation requests (going off current wording in the Standard).

/Leigh


"Bo Persson" <bop@gmb.dk> wrote in message
news:7i9003F2odpauU1@mid.individual.net...
>
> Leigh Johnston wrote:
>>
>> Microsoft will not fix what I consider a bug in VC++ STL
>> implementation until there is clarification in the standard of what
>> container::max_size() actually means, or more specifically how it
>> relates to allocator::max_size().
>>
>> The standard states that allocator::max_size() is the largest value
>> that can be passed to allocator::allocate whilst
>> container::max_size() is largest possible size() of the container.
>> VC++ STL assumes that container::max_size() is equivalent to
>> allocator::max_size() which I think is incorrect.  g++ assumes that
>> container::max_size() is different to allocator::max_size() which I
>> think is correct.  When writing a custom allocator it is possible
>> that the allocator might return 1 for allocator::max_size() even
>> though you can allocate more than one element via multiple calls to
>> allocator::allocate (consider a non-contiguous chunk/pool
>> allocator).
>> Could we have clarification in the standard to satisfy Microsoft?
>>
>> The VC++ bug is
>> https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=490955
>>
>> /Leigh
>
> The committee has already considered another request to improve the
> wording, but declined.
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#197
>
>
> I believe the intent was to have an (ball park) upper limit to the
> allocation size. If you try to allocate more than
> allocator::max_size(), you are certain that this will fail. This
> doen't mean that max_size() - 1 will succeed.
>
> For example, the std::allocator<T> supplied by Microsoft effectively
> returns numeric_limits<size_t>::max() / sizeof(T), which is a gross
> over estimation, considering that the OS reserves half the address
> space for itself.
>
> That's about how precise the function is.
>
>
> Bo Persson

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Mon, 28 Sep 2009 03:35:02 CST
Raw View
Which behaviour is correct given the following code, g++ or VC++?
They cannot both be correct.

#include <iostream>
#include <list>

template <typename T>
struct hmm : std::allocator<T>
{
  hmm() {}
  hmm(const hmm& other) : std::allocator<T>(other) {}
  template <typename U>
  hmm(const hmm<U>& other) : std::allocator<T>(other) {}
  typename std::allocator<T>::size_type max_size() const { return 1; }
  template<class _Other>
  struct rebind { typedef hmm<_Other> other; };
};

int main()
{
  typedef std::list <int, hmm<int> > container;
  container list;
  list.push_back(1);
  list.push_back(1);
  std::cout << "container::size() = " << list.size() << std::endl;
  std::cout << "container::max_size() = " << list.max_size() << std::endl;
  std::cout << "container::allocator_type::max_size() = " <<
container::allocator_type().max_size() << std::endl;
}

g++ outputs:

container::size() = 2
container::max_size() = 4294967295
container::allocator_type::max_size() = 1

VC++ throws an exception on the second push_back.

They cannot both be correct.

/Leigh


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Bo Persson" <bop@gmb.dk>
Date: Mon, 28 Sep 2009 18:45:34 CST
Raw View
Leigh Johnston wrote:
> Which behaviour is correct given the following code, g++ or VC++?
> They cannot both be correct.
>
> #include <iostream>
> #include <list>
>
> template <typename T>
> struct hmm : std::allocator<T>
> {
>  hmm() {}
>  hmm(const hmm& other) : std::allocator<T>(other) {}
>  template <typename U>
>  hmm(const hmm<U>& other) : std::allocator<T>(other) {}
>  typename std::allocator<T>::size_type max_size() const { return 1;
>  } template<class _Other>
>  struct rebind { typedef hmm<_Other> other; };
> };
>
> int main()
> {
>  typedef std::list <int, hmm<int> > container;
>  container list;
>  list.push_back(1);
>  list.push_back(1);
>  std::cout << "container::size() = " << list.size() << std::endl;
>  std::cout << "container::max_size() = " << list.max_size() <<
>  std::endl; std::cout << "container::allocator_type::max_size() = "
> << container::allocator_type().max_size() << std::endl;
> }
>
> g++ outputs:
>
> container::size() = 2
> container::max_size() = 4294967295
> container::allocator_type::max_size() = 1
>
> VC++ throws an exception on the second push_back.
>
> They cannot both be correct.
>
> /Leigh

FWIW, this seems to be the behavior of g++ 3, where I have 3.4.6
looking like this:

       /**  Returns the size() of the largest possible %list.  */
       size_type
       max_size() const
       { return size_type(-1); }

On the other hand, the latest 4.4.1 has changed this into:

       /**  Returns the size() of the largest possible %list.  */
       size_type
       max_size() const
       { return _M_get_Node_allocator().max_size(); }


None of these seems extremely accurate, but using the allocator
max_size at least seems to be the current trend.


Bo Persson



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Tue, 29 Sep 2009 12:00:43 CST
Raw View
Looks like I will have to change my custom pool allocator max_size() to
return a stupidly large value instead of returning 1 even though the
standard says that max_size() "Returns: the largest value that can
meaningfully be passed to X::allocate()".

/Leigh


"Bo Persson" <bop@gmb.dk> wrote in message
news:7ic5rmF31k7uqU1@mid.individual.net...
> Leigh Johnston wrote:
>> Which behaviour is correct given the following code, g++ or VC++?
>> They cannot both be correct.
>>
>> #include <iostream>
>> #include <list>
>>
>> template <typename T>
>> struct hmm : std::allocator<T>
>> {
>>  hmm() {}
>>  hmm(const hmm& other) : std::allocator<T>(other) {}
>>  template <typename U>
>>  hmm(const hmm<U>& other) : std::allocator<T>(other) {}
>>  typename std::allocator<T>::size_type max_size() const { return 1;
>>  } template<class _Other>
>>  struct rebind { typedef hmm<_Other> other; };
>> };
>>
>> int main()
>> {
>>  typedef std::list <int, hmm<int> > container;
>>  container list;
>>  list.push_back(1);
>>  list.push_back(1);
>>  std::cout << "container::size() = " << list.size() << std::endl;
>>  std::cout << "container::max_size() = " << list.max_size() <<
>>  std::endl; std::cout << "container::allocator_type::max_size() = "
>> << container::allocator_type().max_size() << std::endl;
>> }
>>
>> g++ outputs:
>>
>> container::size() = 2
>> container::max_size() = 4294967295
>> container::allocator_type::max_size() = 1
>>
>> VC++ throws an exception on the second push_back.
>>
>> They cannot both be correct.
>>
>> /Leigh
>
> FWIW, this seems to be the behavior of g++ 3, where I have 3.4.6
> looking like this:
>
>       /**  Returns the size() of the largest possible %list.  */
>       size_type
>       max_size() const
>       { return size_type(-1); }
>
> On the other hand, the latest 4.4.1 has changed this into:
>
>       /**  Returns the size() of the largest possible %list.  */
>       size_type
>       max_size() const
>       { return _M_get_Node_allocator().max_size(); }
>
>
> None of these seems extremely accurate, but using the allocator
> max_size at least seems to be the current trend.
>
>
> Bo Persson
>
>
>
> --
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]
>


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Sean Hunt <rideau3@gmail.com>
Date: Tue, 6 Oct 2009 12:57:15 CST
Raw View
On Sep 29, 11:00 am, "Leigh Johnston" <le...@i42.co.uk> wrote:
> Looks like I will have to change my custom pool allocator max_size() to
> return a stupidly large value instead of returning 1 even though the
> standard says that max_size() "Returns: the largest value that can
> meaningfully be passed to X::allocate()".
>
> /Leigh

Perhaps you should submit to Microsoft (and file a G++ bug, from the
looks of it) that their implementation should respect the intended
meaning of allocator_type::max_size() for containers that only need to
allocate one element at a time anyways. A container like vector or
string would be expected to have a max_size of allocator_type::max_size
().

Sean Hunt


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]