Topic: allocators...exceptions...new/delete


Author: dhruvbird@gmx.net ("Dhruv")
Date: Fri, 25 Jul 2003 15:30:54 +0000 (UTC)
Raw View
On Thu, 17 Jul 2003 05:19:10 +0000, Markus Mauhart wrote:

> "Richard Smith" <richard@ex-parrot.com> wrote ...
>>
>> Personally, I don't think that the copy or conversion (template)
>> constructors for an Allocator should throw.  This is not a requirement
> made
>> by the Standard, merely a rule-of-thumb I've found through experience.
> The
>> reason is that many operations within STL containers, etc. copy and
>> sometimes convert allocators very frequently, and so this should be
> very
>> efficient.
>
> For the problem of "convert allocators very frequently" I've recently
> used an IMHO interesting technique.
> The situation is that I create a one-size POOL, size known at compile
> time. I want to use this POOL for std::set. I think it is large enough
> for set-nodes, and I can verify this at compiletime, but OTOH inside
> std::set there are a couple of conversions to alloc<bigger_type>, but
> which IMHO is then not used for allocation ... I want to verify this
> assumption at compiletime too.
> My solution:
>

Let me see if I got you right here. You are trying to verify at compile
time if your node allocator's node size is big enough for std::set's
nodes. And, you are also trying to verify at compile time agian if
std::set uses a rebind version of your allocator to actually allocate some
node structure, which is bigger than the std::set's node size, or to be
more specific, more than the minumum size of your allocator's maximum
limit to what size it can accept. So, basically, it would eliminate the
need to check if x == 1 in the allocate function, and so, no runtime
checks on 'x'. Right?

So, wouldn't that make your allocator highly dependant on the particular
implementation of that STL? All STL implementations will not have the same
name for the set's node? OR am I missing something? Now, if you remove all
of that, and just keep an assert out there, then run the std::set
functions at least once, so that you are sure that they neverr call
allocate with a size of more that 1, then you can later remove that assert
too during the final build. Even that wouldn't wouldn't be necessary, if
you kept the assert in an if block. (This code looks pretty stupid, but it
works!!!!!!).

allocate (size_type x)
{
if (x == 1)
{
return <Allocated memory>.
}
else { assert (false); }
}

With g++ and -O3, the if statement will completely disappear, or even for
that matter, when compiling with any optimizing compiler, because in code,
the allocate function is always called in a way similar to this:

ptr = allocate (1);


What I was looking out for was that if C++ can deduce type template
parameters for functions, then it should be also able to deduce non-type
template parameters for the same. This obviously doesn't work, but, if it
did, then it would be great:

template <size_type n>
pointer allocate (size_type n) //NOTE, n used in bith the parameter as
//template parameter.
{
ConceptCheck<some concept violated>
}

template <size_type n>
pointer allocate<1> (size_type n)
{
//We are 100% sure that n == 1, because of partial template
//specialization.
//This would obviously mean that non-type template parameters would have
//to be deduced at compile time too.
}


Regards,
-Dhruv.






---
[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: 18 Jul 2003 15:26:08 -0400
Raw View
Markus Mauhart wrote:

> IMO default construction of statefull allocators must fail at compile
> time

I agree.  Not only for the reasons you state, but also because it isn't
always possible to provide a meaningful default constructor.  It's a shame
that Table 32 requires a default constructor.  IMHO, I would have made it an
"additional" requirement in 20.1.5/4.

When I've used stateful allocators I've often provided a default constructor
that creates a null allocator, and made it such that all allocations on a
null allocator throw bad_alloc.  I sometimes also provide "safe" boolean
conversions to test whether it is null.  This way, it conforms to the letter
of Table 32, and it allows slightly more flexibility in constructing
allocators:

  my_allocator a;
  if ( condition )
    a = my_allocator( params );
  else if ( other_condition );
    a = my_allocator( other_params );
  else
    a = my_allocator( yet_more_params );
  std::vector<int> v( 32, 42, a );

--
Richard Smith
---
[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: 18 Jul 2003 15:27:11 -0400
Raw View
"James Kuyper" <kuyper@wizard.net> wrote in message
news:8b42afac.0307131332.7d177ddd@posting.google.com...
> "Richard Smith" <richard@ex-parrot.com> wrote in message
news:<bemosh$apc$1$8300dec7@news.demon.co.uk>...
> ..
>  > Absolutely.  There are requirements on the template parameters of the
>  > allocator.  There isn't even a requirement that it be templated, though
it's
>  > hard to think how else it could be implemented.
>
> Here's a basic scheme for having a non-templated allocator class:
>
> IntAllocator is a non-template class with a value_type of 'int'.
> GenAllocator<class T> is a templated class.
> IntAllocator::rebind<U>::other has exactly the same implementation as
> GenAllocator<T>::rebind<U>::other. For U==int, they are typedefs for
> IntAllocator; otherwise, they are typedefs for GenAllocator<U>.
> IntAllocator therefore qualifies as an allocator, and GenAllocator<T>
> qualifies as a allocator class for all values of 'T' other than 'int'.

Perhaps I should have said usefully implemented ;-).

I'm not sure what this would gain that a specialisation of GenAllocator<T>
for T = int wouldn't achieve.

--
Richard Smith
---
[ 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: "Markus Mauhart" <markus.mauhart@nospamm.chello.at>
Date: Mon, 21 Jul 2003 03:42:50 GMT
Raw View
"Richard Smith" <richard@ex-parrot.com> wrote ...
> Markus Mauhart wrote:
>
> > IMO default construction of statefull allocators must fail at compile
> > time
>
> I agree.  Not only for the reasons you state, but also because it isn't
> always possible to provide a meaningful default constructor.

I've allmost forgotten this one ... so we have enough good arguments ;-)
IMO it's only an oversight, I dont think there will be troubles to fix it.

> It's a shame that Table 32 requires a default constructor.
> IMHO, I would have made it an "additional" requirement in 20.1.5/4.

Yes, this seems to be the right place.

> When I've used stateful allocators I've often provided a default constructor
> that creates a null allocator, and made it such that all allocations on a
> null allocator throw bad_alloc. I sometimes also provide "safe" boolean
> conversions to test whether it is null.  This way, it conforms to the letter
> of Table 32, and it allows slightly more flexibility in constructing
> allocators:
>
>   my_allocator a;
>   if ( condition )
>     a = my_allocator( params );
>   else if ( other_condition );
>     a = my_allocator( other_params );
>   else
>     a = my_allocator( yet_more_params );
>   std::vector<int> v( 32, 42, a );

in my case the safe default construction or other ctor-args are one
level below, like ...

  ENGINE                e     ;//no args -> alloc() return 0 in any case.
  allocator_from_engine a (e) ;//ENGINE gives 0 => allocator throws bad_alloc
  e.restart (args)            ;//now it is ready.

But despite the some quirks in the standard w.r.t. allocators,
IMO its functionality and advantage is enormeous, my respect to
the people being responsible for it.


Regards,
Markus.



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Andy Sawyer <andys@despammed.com>
Date: Mon, 21 Jul 2003 03:55:23 GMT
Raw View
In article <pan.2003.07.14.18.42.47.163218@gmx.net>,
 on Fri, 18 Jul 2003 04:55:12 GMT,
 "Dhruv" <dhruvbird@gmx.net> wrote:

> On Sat, 12 Jul 2003 09:24:52 -0400, James Kuyper wrote:
>
> >> Yes, in fact, I have the 1996 draft copy.
> >
> > Get the real standard. There are LOTS of difference between that draft
> > and the final version.
> >
>
> I will ASA I find someone to sponsor it :-) I wonder if the guys at the
> ansi standard organization give any sort of student discount?

It's US$18 - that isn't a lot, even on a student budget.

[snip]

> Yes, I've got to stop making stupid assumptions.

There's a oft-quoted reason "assume" is spelt the way it is ;)

Regards,
 Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: kuyper@wizard.net (James Kuyper)
Date: Mon, 21 Jul 2003 04:00:44 GMT
Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message news:<bf5rh0$7m3$1$8300dec7@news.demon.co.uk>...
 > "James Kuyper" <kuyper@wizard.net> wrote in message
 > news:8b42afac.0307131332.7d177ddd@posting.google.com...
..
 > > Here's a basic scheme for having a non-templated allocator class:
 > >
 > > IntAllocator is a non-template class with a value_type of 'int'.
 > > GenAllocator<class T> is a templated class.
 > > IntAllocator::rebind<U>::other has exactly the same implementation as
 > > GenAllocator<T>::rebind<U>::other. For U==int, they are typedefs for
 > > IntAllocator; otherwise, they are typedefs for GenAllocator<U>.
 > > IntAllocator therefore qualifies as an allocator, and GenAllocator<T>
 > > qualifies as a allocator class for all values of 'T' other than 'int'.
 >
 > Perhaps I should have said usefully implemented ;-).
 >
 > I'm not sure what this would gain that a specialisation of GenAllocator<T>
 > for T = int wouldn't achieve.

I'm not sure, either. However, it does have one fewer template
parameter. Which means that it's possible for another template, by use
of template template parameters, to work differently for IntAllocator
than it would for a specialization of GenAllocator<int>.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Andy Sawyer <andys@despammed.com>
Date: Mon, 21 Jul 2003 05:31:30 GMT
Raw View
In article <pan.2003.07.15.04.01.45.379363@gmx.net>,
  on Thu, 17 Jul 2003 14:30:32 GMT,
  "Dhruv" <dhruvbird@gmx.net> wrote:

 > On Sat, 12 Jul 2003 09:23:19 -0400, Andy Sawyer wrote:
 >
 >  > In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
 >  >  on 11 Jul 2003 08:49:35 -0400,
 >  >  "Dhruv" <dhruvbird@gmx.net> wrote:
 >  >
 >  >> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
 >  >>
 >  >> Just another quick question: Are allocators allowed to be
 >  >> templated around more that one template parameter?
 >  >
 >  > In the case of std::allocator, the answer is clearly no (due to the
 >  > template template parameter issue).
 >  > For other allocators, however, I see no reason why not - although making
 >  > rebind do the right thing might be interesting.
 >  >
 >
 > Thanks.

You're welcome.

 >  >> Also, with such a design, template template parameters would not
 >  >> work, or would they?
 >  >
 >  > It rather depends on what you mean...
 >
 > I have replied to Richard Smith saying what I mean. Please have a look at
 > it and tell me.

I have done. I now suspect that you're thinking that my_allocator<T1,T2>
isn't a drop-in replacement for std::allocator in the case where
something takes std::allocator as a template parameter? If that is what
you're getting at then you're right - they won't work. However,
std::containers don't take allocator templates as
template-template-parameters, they take allocators (often
specialisations of the std::allocator template) as template parameters
(If you can make sense of that sentence, then you're doing better than I
am :)


In other words, when you write:

std::vector< int > v;

The compiler knows you mean

std::vector<int, std::allocator<int> > v;

and std::allocator<int> isn't a template - it's a specialisation of
allocator, and is actually a type. If the interface to std::vector were:

template<typename T,
         template <typename U> class Allocator>
class vector
{
  // ...

then you'd have problems. But it isn't, so you don't :)

I hope that makes SOME kind of sense - I wrote it and whilst I know what
I mean, I'm struggling to read it!

Regards,
  Andy<S> ;)
--
"Light thinks it travels faster than anything but it is wrong. No matter
  how fast light travels it finds the darkness has always got there first,
  and is waiting for it."                  -- Terry Pratchett, Reaper Man

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Andy Sawyer <andys@despammed.com>
Date: Mon, 21 Jul 2003 05:38:13 GMT
Raw View
In article <pan.2003.07.15.04.00.36.238003@gmx.net>,
  on Thu, 17 Jul 2003 14:31:03 GMT,
  "Dhruv" <dhruvbird@gmx.net> wrote:

 > On Sat, 12 Jul 2003 09:24:06 -0400, Richard Smith wrote:
 >
 >  > If you want to do something like
 >  >
 >  >   template <class T, template <class> class Policy>
 >  >   class my_allocator;
 >  >
 >  > this is fine.
 >  >
 >  > If you want to do
 >  >
 >  >   template <class T> class my_allocator;
 >  >   std::vector< int, my_allocator > v;
 >  >
 >  > it is not OK.
 >
 > I haven't quite understood what you're trying to say here, and why won;t
 > the 2nd eg. work.

The second example won't work because my_allocator isn't a type, and the
second template parameter to vector must be a type.

std::vector<int,my_allocator<int> > v;

will work (assuming my_allocator does the right thing!)

 > What I had in mind was something like this:
 >
 > #include <memory>
 > #include <nstl/list_alloc.hpp>
 > #include <boost/pool/pool.hpp>
 >
 > template <template <class type> class some_alloc >
 > struct foo {
 >    //type t;
 >    some_alloc<int> ia;
 > };
 >
 > int main ()
 > {
 >    foo <nstd::list_node_allocator> f;
 >    foo <boost::fast_pool_allocator> f1;
 > }

Clearly without seeing the declarations of nstd::list_node_allocator or
boost::fast_pool_allocator we can't say for sure.

boost::fast_pool_allocator looks something like:

template<typename T,
         typename UserAllocator = default_user_allocator_new_delete>
class fast_pool_allocator
{
//...
};

In which case, the declaration of 'f1' is invalid (mismatch on template
template parameter argument count). If we had template typedefs, you
could probably solve this with something like:

template<typename T>
    typedef boost::fast_pool_allocator<T,
            default_user_allocator_new_delete> boost_fast_pool_allocator;

And then write:

   foo<boost_fast_pool_allocator> f1;

But since we DON'T have template typedefs, you may find some mileage in:

template<typename T>
struct boost_fast_pool_allocator
  : public boost::fast_pool_allocator<T,
            default_user_allocator_new_delete>
{
// you need to implement a bunch of stuff as forwarding functions -
// particuarly constructors, and probably rebind
};

I'm not familiar with nstd::list_node_allocator, but will assume it
looks something like:

namespace nstd {

   template<typename T> // Note: Single template argument
   struct list_node_allocator {
// stuff
   };
}

Then 'f' should be fine (assuming that list_node_allocator presents the
appropriate interface for foo :)

 > That would eliminate the need to pass the type explicitly, and also, the
 > rebind hack would disappear in case of a list, or the map, etc......

I don't consider rebind to be a hack, more like the least inelegant
solution to a problem which appears to have no elegant solutions :).
[sidetrack: IMHO, the biggest problem with rebind is that it is not well
specified how containers may use it - and what they may (or may not) do
with the allocator it returns (specifically, may a container repeatedly
call rebind each time it needs an allocator for an alternate type, or
should it do it once at construction time and keep that rebound
allocator around?). I know of library implementations which fall into
either category (my preference is for the single-call option, but I
wouldn't care too much either way as long as I knew which technique was
going to be used :)]

 > I'm not too sure about whether the code is even correct. Please tell
 > me if it's correct, because I don't trust g++ much on template issues.

As I say above, assuming nstd::list_node_allocator takes one template
argument, then f is fine. Since boost::fast_pool_allocator takes two
template arguments, then f1 is invalid.

If in doubt, you can always try feeding your code to the Comeau Online
compiler at http://www.comeaucomputing.com/tryitout/ (remember to ensure
the "Compile in strict mode" option is selected. Or, even better, send
them some money and get your own copy (Comeau C++ is PAINFULLY
inexpensive at US$50/seat :)

 > Something that I'm quite sure about is that the boost allocator example
 > (f1 object thing) does not compile because of the the n number of
 > parameters that it has.

That is correct.

 > One more thing: Is it legal to access type within the struct, as in, can
 > you do something like this isnode the struct:
 >
 > some_alloc<type> alloc;
 >
 > It doesn't seem to work on g++.

If you mean what I think you mean, which is:

template< template<class type> some_alloc >
{
    some_alloc<type> alloc;
};

Then no, it doesn't "work" - depending on what you mean by "work" -
since "type" isn't _actually_ a type, it's a "placeholder" for a
template argument.  What would you expect the above to do?

you can write:

template< template<class type> some_alloc >
stuct thing
{
    some_alloc<int>         int_alloc;
    some_alloc<float>       float_alloc;
    some_alloc<std::string> string_alloc;

// or even:
    template<typename X>
    struct node { };
    some_alloc<node<int> >  node_alloc;
};

Those are fine, because you're instantiating some_alloc on a type.


Regards,
  Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
  how fast light travels it finds the darkness has always got there first,
  and is waiting for it."                  -- Terry Pratchett, Reaper Man

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Thu, 17 Jul 2003 05:18:27 GMT
Raw View
On Sat, 12 Jul 2003 09:23:19 -0400, Andy Sawyer wrote:

> In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
>  on 11 Jul 2003 08:49:35 -0400,
>  "Dhruv" <dhruvbird@gmx.net> wrote:
>
>> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>>
>> Just another quick question: Are allocators allowed to be templated around
>> more that one template parameter?
>
> In the case of std::allocator, the answer is clearly no (due to the
> template template parameter issue).
> For other allocators, however, I see no reason why not - although making
> rebind do the right thing might be interesting.
>

Thanks.


>> Also, with such a design, template template parameters would not work, or
>> would they?
>
> It rather depends on what you mean...
>

I have replied to Richard Smith saying what I mean. Please have a look at
it and tell me.

Regards,
-Dhruv.

On Sat, 12 Jul 2003 09:23:19 -0400, Andy Sawyer wrote:

> In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
>  on 11 Jul 2003 08:49:35 -0400,
>  "Dhruv" <dhruvbird@gmx.net> wrote:
>
>> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>>
>> Just another quick question: Are allocators allowed to be templated around
>> more that one template parameter?
>
> In the case of std::allocator, the answer is clearly no (due to the
> template template parameter issue).
> For other allocators, however, I see no reason why not - although making
> rebind do the right thing might be interesting.
>

Thanks.


>> Also, with such a design, template template parameters would not work, or
>> would they?
>
> It rather depends on what you mean...
>

I have replied to Richard Smith saying what I mean. Please have a look at
it and tell me.

Regards,
-Dhruv.



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Markus Mauhart" <markus.mauhart@nospamm.chello.at>
Date: Thu, 17 Jul 2003 05:18:44 GMT
Raw View
"Richard Smith" <richard@ex-parrot.com> wrote ...
>
> Finally, if your STL properly supports stateful allocators (they are
not
> required to: see 20.1.5/4), and you are prepared to tie yourself to
such
> STLs, you could make a default constructed allocator always fail to
> allocate, and provide a custom constructor that correctly initialises
the
> object.

IMO default construction of statefull allocators must fail at compile
time, cause this is the only way to catch faulty STL-implementations
or other allocator clients that contain the bug not to copy-construct
allocators from their internal copy, but instead use default
construction.
This 'bug' is an allmost unavoidable sideeffect of the containers need
to support both statefull and "invisible" stateless allocators,
"invisible"
means that all parameters of type 'alloc_type' have the default argument
"x = alloc_type()".
Both VC7x STL and GCC3.2xx STL contain this bug inside their
link::sort<>
function ... it's a bug cause both STL implementations deliberatly make
efforts (and VC7x explicitely says this) to be compatible with statefull
allocators. Otherwise AFAICS both STL's work well with statefull
allocators.

Another bug you can catch only with this "no-def-ctor" policy is a
defect
in current basic_stringstream, saying that str(), if content is empty,
shall return "basic_string()" .. instead it has to be something like
"basic_string (this->get_allocator())"

Otherwise AFAICS the complete c++98 is 'ready' for statefull allocators,
cause all containers with allocator template parameter have
corresponding
constructors taking A COPY IF YOU PROVIDE IT.

IOW, when 20.1.5 currently even requires default ctors for allocators,
this is a defect w.r.t. statefull allocators.


Regards,
Markus.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Markus Mauhart" <markus.mauhart@nospamm.chello.at>
Date: Thu, 17 Jul 2003 05:19:10 GMT
Raw View
"Richard Smith" <richard@ex-parrot.com> wrote ...
>
> Personally, I don't think that the copy or conversion (template)
> constructors for an Allocator should throw.  This is not a requirement
made
> by the Standard, merely a rule-of-thumb I've found through experience.
The
> reason is that many operations within STL containers, etc. copy and
> sometimes convert allocators very frequently, and so this should be
very
> efficient.

For the problem of "convert allocators very frequently" I've recently
used an IMHO interesting technique.
The situation is that I create a one-size POOL, size known at compile
time. I want to use this POOL for std::set. I think it is large enough
for set-nodes, and I can verify this at compiletime, but OTOH inside
std::set there are a couple of conversions to alloc<bigger_type>, but
which IMHO is then not used for allocation ... I want to verify this
assumption at compiletime too.
My solution:

DATA ...;
struct tree_node {void* p[4] ;DATA data ;};
POOL pool (sizeof(tree_node));
typedef allocator_fixed <POOL ,e_no_check ,sizeof(tree_node) ,DATA>
ALLOC;
set <DATA ,less<DATA> ,ALLOC> my_set;

The e_no_check-argument means "dont perform runtime checks" ... cause
I assume "node-allocation-behaviour" <=> allocate's argument is '1'.
But cause of the size_t template paramter in allocator_fixed, it knows
at compiletime that for T with 'sizeof(T) > t_size' it cannot allocate:

    template <class T_POOL ,E_NO_CHECK t_no_check ,size_t t_size ,class
T>
    T* allocator_fixed::allocate (size_type x) const throw(bad_alloc)
    {
    precond_class <sizeof(T) >= 4 || !t_no_check> ::qwe;
        //I assume that 'sizeof(T) < 4' is a strong hint to expect 'x !=
1'.
        // => x MUST then be checked at runtime.
    precond_class <sizeof(T) <=  t_size> ::qwe;
    ASSERT (chunk_size(*m) >= t_size);
    void* res = 0   ;
    if (t_no_check || t_size >= x * sizeof(T))
        x , res = chunk_alloc (*m) ;
    if (res) return (T*) res ;
    throw bad_alloc()  ;
    }

Btw, my main reason to absolutely avoid runtime checks or using 'x' at
runtime here was to make this "set <alloc_fixed <POOL>...>" (allmost)
binary indistinguishable from "set
<alloc_full_blown_heap_based_on_POOL>".
So with VC's linker, all set-functions only relying on [de]allocate()
are 'overlayed' with the same functions having different sizeof(T)
or one of the two mentioned allocator's.


Regards,
Markus.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: kuyper@wizard.net (James Kuyper)
Date: Thu, 17 Jul 2003 05:19:15 GMT
Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message news:<bemosh$apc$1$8300dec7@news.demon.co.uk>...
..
 > Absolutely.  There are requirements on the template parameters of the
 > allocator.  There isn't even a requirement that it be templated, though it's
 > hard to think how else it could be implemented.

Here's a basic scheme for having a non-templated allocator class:

IntAllocator is a non-template class with a value_type of 'int'.
GenAllocator<class T> is a templated class.
IntAllocator::rebind<U>::other has exactly the same implementation as
GenAllocator<T>::rebind<U>::other. For U==int, they are typedefs for
IntAllocator; otherwise, they are typedefs for GenAllocator<U>.
IntAllocator therefore qualifies as an allocator, and GenAllocator<T>
qualifies as a allocator class for all values of 'T' other than 'int'.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 17 Jul 2003 05:19:22 GMT
Raw View
In message <8b42afac.0307110927.4628a542@posting.google.com>, James
Kuyper <kuyper@wizard.net> writes
>> Yes, in fact, I have the 1996 draft copy.
>
>Get the real standard. There are LOTS of difference between that draft
>and the final version.

And even more now that the C++ Standard incorporates TC1.

--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow      ACCU



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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                       ]
------------ And now a word from our sponsor ---------------------
For a secure high performance FTP using SSL/TLS encryption
upgrade to SurgeFTP
----  See http://netwinsite.com/sponsor/sponsor_surgeftp.htm  ----




Author: "Dhruv" <dhruvbird@gmx.net>
Date: Thu, 17 Jul 2003 14:30:32 GMT
Raw View
On Sat, 12 Jul 2003 09:23:19 -0400, Andy Sawyer wrote:

 > In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
 >  on 11 Jul 2003 08:49:35 -0400,
 >  "Dhruv" <dhruvbird@gmx.net> wrote:
 >
 >> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
 >>
 >> Just another quick question: Are allocators allowed to be templated around
 >> more that one template parameter?
 >
 > In the case of std::allocator, the answer is clearly no (due to the
 > template template parameter issue).
 > For other allocators, however, I see no reason why not - although making
 > rebind do the right thing might be interesting.
 >

Thanks.


 >> Also, with such a design, template template parameters would not work, or
 >> would they?
 >
 > It rather depends on what you mean...
 >

I have replied to Richard Smith saying what I mean. Please have a look at
it and tell me.

Regards,
-Dhruv.








      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Thu, 17 Jul 2003 14:31:03 GMT
Raw View
On Sat, 12 Jul 2003 09:24:06 -0400, Richard Smith wrote:

 > "Dhruv" <dhruvbird@gmx.net> wrote in message
 > news:pan.2003.07.10.18.19.19.500436@gmx.net...
 >> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
 >>
 >> Just another quick question: Are allocators allowed to be templated around
 >> more that one template parameter?
 >
 > Absolutely.  There are requirements on the template parameters of the
 > allocator.  There isn't even a requirement that it be templated, though it's
 > hard to think how else it could be implemented.  Basically, as long as you
 > can make rebind<> work, you're fine.
 >

Ok, thanks.


 >> Also, with such a design, template template parameters would not work, or
 >> would they?
 >
 > Not sure how you want to use template template parameters.
 >
 > If you want to do something like
 >
 >   template <class T, template <class> class Policy>
 >   class my_allocator;
 >
 > this is fine.
 >
 > If you want to do
 >
 >   template <class T> class my_allocator;
 >   std::vector< int, my_allocator > v;
 >
 > it is not OK.

I haven't quite understood what you're trying to say here, and why won;t
the 2nd eg. work.


What I had in mind was something like this:

#include <memory>
#include <nstl/list_alloc.hpp>
#include <boost/pool/pool.hpp>

template <template <class type> class some_alloc >
struct foo {
   //type t;
   some_alloc<int> ia;
};

int main ()
{
   foo <nstd::list_node_allocator> f;
   foo <boost::fast_pool_allocator> f1;
}




That would eliminate the need to pass the type explicitly, and also, the
rebind hack would disappear in case of a list, or the map, etc......

I'm not too sure about whether the code is even correct. Please tell me if
it's correct, because I don't trust g++ much on template issues.

Something that I'm quite sure about is that the boost allocator example
(f1 object thing) does not compile because of the the n number of
parameters that it has.

One more thing: Is it legal to access type within the struct, as in, can
you do something like this isnode the struct:

some_alloc<type> alloc;

It doesn't seem to work on g++.


Regards,
-Dhruv.








      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Fri, 18 Jul 2003 04:55:12 GMT
Raw View
On Sat, 12 Jul 2003 09:24:52 -0400, James Kuyper wrote:

>> Yes, in fact, I have the 1996 draft copy.
>
> Get the real standard. There are LOTS of difference between that draft
> and the final version.
>

I will ASA I find someone to sponsor it :-) I wonder if the guys at the
ansi standard organization give any sort of student discount?

[snip]......


>> What is the advantage of using such stateful allocators?
>
> On simple kind of stateful allocator uses a new, distinct memory pool
> each time a new instance of the allocator is created, and shares that
> pool with every instance created by copy construction, copy
> assignment, and conversion. Instances that use different memory pools
> are inequivalent, because they don't have access to each other's
> memory pools.
>

So, basically, it's like per-class allocators.


> ...
>> The problem that I had was that I was assuming that since nothing was
>> mentioned about constructors of allocators throwing, I was assuming
>> that
>> that requirement was the same as std::allocator, and that was
>> stopping me
>> from desinging the allocatior properly.
>
> Just read section 20.1.5; don't infer any additional requirements just
> because they apply to the default allocator.

Yes, I've got to stop making stupid assumptions.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Fri, 18 Jul 2003 04:55:22 GMT
Raw View
On Sat, 12 Jul 2003 09:23:19 -0400, Andy Sawyer wrote:

> In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
>  on 11 Jul 2003 08:49:35 -0400,
>  "Dhruv" <dhruvbird@gmx.net> wrote:
>
>> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>>
>> Just another quick question: Are allocators allowed to be templated
>> around
>> more that one template parameter?
>
> In the case of std::allocator, the answer is clearly no (due to the
> template template parameter issue).
> For other allocators, however, I see no reason why not - although
> making
> rebind do the right thing might be interesting.
>

Thanks.


>> Also, with such a design, template template parameters would not
>> work, or
>> would they?
>
> It rather depends on what you mean...
>

I have replied to Richared Smith saying what I mean. Please have a look
at
it and tell me.

Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Fri, 18 Jul 2003 04:55:24 GMT
Raw View
On Sat, 12 Jul 2003 09:24:06 -0400, Richard Smith wrote:

> "Dhruv" <dhruvbird@gmx.net> wrote in message
> news:pan.2003.07.10.18.19.19.500436@gmx.net...
>> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>>
>> Just another quick question: Are allocators allowed to be templated
>> around
>> more that one template parameter?
>
> Absolutely.  There are requirements on the template parameters of the
> allocator.  There isn't even a requirement that it be templated,
> though it's
> hard to think how else it could be implemented.  Basically, as long as
> you
> can make rebind<> work, you're fine.
>

Ok, thanks.


>> Also, with such a design, template template parameters would not
>> work, or
>> would they?
>
> Not sure how you want to use template template parameters.
>
> If you want to do something like
>
>   template <class T, template <class> class Policy>
>   class my_allocator;
>
> this is fine.
>
> If you want to do
>
>   template <class T> class my_allocator;
>   std::vector< int, my_allocator > v;
>
> it is not OK.

I haven't quite understood what you're trying to say here, and why won;t
the 2nd eg. work.


What I had in mind was something like this:

#include <memory>
#include <nstl/list_alloc.hpp>
#include <boost/pool/pool.hpp>

template <template <class type> class some_alloc >
struct foo {
   //type t;
   some_alloc<int> ia;
};

int main ()
{
   foo <nstd::list_node_allocator> f;
   foo <boost::fast_pool_allocator> f1;
}




That would eliminate the need to pass the type explicitly, and also, the
rebind hack would disappear in case of a list, or the map, etc......

I'm not too sure about whether the code is even correct. Please tell me
if
it's correct, because I don't trust g++ much on template issues.

Something that I'm quite sure about is that the boost allocator example
(f1 object thing) does not compile because of the the n number of
parameters that it has.

One more thing: Is it legal to access type within the struct, as in, can
you do something like this isnode the struct:

some_alloc<type> alloc;

It doesn't seem to work on g++.


Regards,
-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: ron@sensor.com ("Ron Natalie")
Date: Fri, 11 Jul 2003 01:39:29 +0000 (UTC)
Raw View
""Dhruv"" <dhruvbird@gmx.net> wrote in message news:pan.2003.07.10.18.32.15.260355@gmx.net...
> On Tue, 24 Jun 2003 03:39:30 +0000, Andy Sawyer wrote:
>  So, this means that now, new int[0] can fail? So, what, will it throw
> std::bad_alloc()?

Yes and yes.

> Also, is the 2nd part trying to say this:?
>
> Suppose you have something like this:
>
> int *pint = new int[0];
> delete pint;
> pint = new int[0];
>
> Meaning that pint now can (could) hold the same value that it held before
> the call to delete?
>
Precisely.   The return of new is always unique from any currently undeleted
new return (even if when it's a zero sized array).

Since there is almost always some overhead associated with keeping track of even
a zero sized allocation to guarantee uniqueness, it's possible that failure to allocate
this overhead internally might throw bad_alloc.

A common (but perhaps not optimal way) of handling this is just to set the size to 1 if
it is zero in the allocator.


---
[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Fri, 11 Jul 2003 06:34:00 GMT
Raw View
On Wed, 09 Jul 2003 19:32:56 -0400, Richard Smith wrote:

[snip]......

> Precisely.  What I said was that I couldn't see a requirement for allocators
> in general (i.e. the Allocator concept) not to throw on default construction
> or copying.  You are trying to write a new allocator, i.e. something that
> models that Allocator concept without being std::allocator, and so this is
> irrelevant.  Hence why I said ...
>
> | Perhaps you're thinking of the requirement that std::allocator's default
> | and copy constructors do not throw?
>
> ... in my previous email.
>
>>  > Table 32 only states that deallocate mustn't throw.
>>
>> Where is Table 32?
>
> On page 356 of the ISO Standard, in section 20.1.5,
> [lib.allocator.requirements], "Allocator requirements".
>

Yes, got it thanks.


>>  > This suggests to me that everything else can throw an
>>  > exception.  This is in keeping with 17.4.3.6/2 which says that
> operations
>>  > may throw unless otherwise specified, which talks about requirements of
>>  > template arguments.
>>
>> I have only upto 17.3.4.8,
>
> Maybe your using a draft copy of the Standard?  If so, you really should buy
> a real copy -- it's not expensive and contains the definitive answer to
> (almost) all questions like this.
>

Yes, in fact, I have the 1996 draft copy.

>> where it says:
>> 3 Any of the functions defined in the C++ Standard library that  do  not
>>    have   an  exception-specification  may  throw  implementation-defined
>>    exceptions.33)  An  implementation may strengthen this implicit excep-
>>    tion-specification by adding an explicit one.34)
>>
>> Is this what you are talking about?
>
> No, I'm talking about the third bullet point paragraph 2 of 17.4.3.6,
> [lib.res.on.functions], "Other functions":
>
> | In particular, the effects are undefined in the following
> | cases: [...]
> |
> |  * for types used as template arguments when instantiating
> |    a template component,

"if the operations on the type do not implement the semantics of the
applicable Requirements subclause (20.1.5, 23.1, 24.1, 26.1). "

What exactly do you mean by this?



> |    Operations on such
> |    types can report a failure by throwing an exception unless
> |    otherwise specified.
>
> This is sections talks about operations on user-supplied template arguments,
> 17.3.4.8 talks about functions defined in the Standard Library, i.e. things
> like std::allocator<>'s copy constructor.
>

I have something similar, but it's given as 17.3.3.6:
"
2 In particular, the effects are undefined in the following cases:
[snip]......

--for  types  used as template arguments when instantiating a template
    component, if the operations on the type do not implement the seman-
    tics   of   the   applicable  Requirements  subclause  (_lib.alloca-
    tor.requirements_,     _lib.container.requirements_,     _lib.itera-
    tor.requirements_, _lib.numeric.requirements_).

  --if  any of these functions or operations throws an exception, unless
    specifically allowed in the applicable Required behavior  paragraph.
"

[snip].....

> Is the assumption justified?

> Not entirely.  There are two separate things here: the concept of an
> Allocator.  This a generic concept which defines what a general-purpose
> allocator must do.  This is defined in section 20.1.5 of the Standard, and
> in particular in Table 32.  Matt Austern's book, "Generic Programming and
> the STL" covers this idea in section 9.4, which I find more conveniently
> than the Standard.
>
> The second thing is the std::allocator class template.  An instantiation of
> this template is an example of the Allocator concept. (It is usual to say
> std::allocator<T> models the Allocator concept.  You'll notice it is usual
> to capitalise concepts to avoid confusion with their names.)  This means
> that all of the expressions required by the Allocator concept must be legal,
> and that they must have the prescribed semantics.  For example, if a is an
> instance of an allocator, and n is a size_t[*], it must be legal to write
>
>   a.allocate(n);
>
> and this function must return a pointer[*] to memory to hold n objects of
> the value_type of the allocator.  Otherwise it must throw.
>
>   [*]  Actually, I'm glossing over some minor details with these
>        point, but they're not relevant here.
>
> In particular, all the Standard says about copying and default constructing
> Allocators, is that you must be able to do so.  It doesn't say that they
> mustn't throw, and hence by 17.4.3.6/2 they are allowed to.
>
>>  > I'm less convinced about a copy constructor that throws --
>>
>> A templated copy ctor that throws, not the normal copy ctor.
>
> A quick point on terminology:  a templated constructor can never be a copy
> constructor.  [See footnote 106, to 12.8/2.]  Thus in the following example,
> the class implicitly generates a copy-constructor.
>
>   template <class T> class my_alloc {
>    public:
>     template <class U> my_alloc( const my_alloc<U>& other );
>   };
>

Yes. because it cannot stop the default copy ctor for being made (or
whatever) by the compiler, while it does stop the default ctor from being
made (generated) by the compiler. However, to be truthful, I always used
to call them templated copy constructors, now that I know, I'll call them
templated constructors.


> Personally, I don't think that the copy or conversion (template)
> constructors for an Allocator should throw.  This is not a requirement made
> by the Standard, merely a rule-of-thumb I've found through experience. The
> reason is that many operations within STL containers, etc. copy and
> sometimes convert allocators very frequently, and so this should be very
> efficient.  If you're doing something that can throw, the chances are it is
> something relatively inefficient (e.g. allocating memory, etc.), hence my
> suggestion to use a reference counted implementation class.
>

I have an allocator that uses the sam heap for different instances as long
as the parameter around which it is instantiated is the same, while if you
construct an allocator of another type from some other type allocator,
then dynamic memory allocation is involved.

Something like:
nstd::allocator<int> int_a; //Memory is allocated dynamically.
nstd::allocator<int> int_b = int_a; //No dynamic memory allocation.
nstd::allocator<double> double_a = int_b; //Memory is allocated
dynamically.

You can see the sources (partially complete, actually, ot at all complete)
at http://www.geocities.com/dhruvbird/nstl0.2.zip
peek into list_alloc.hpp



>>  > Finally, if your STL properly supports stateful allocators (they are
> not
>>  > required to: see 20.1.5/4),
>>
>> Ok, so these implementation defined allocators are called stateful
>> allocators?
>
> A stateful allocator (I don't think the Standard uses this term, but it is
> used commonly elsewhere) is one that can have internal state.  The STL is
> not required to support such allocators (there is a get-out clause in
> 20.1.5/4), but implementations are "encouraged" to do so and increasingly
> many do.  With a stateless allocator, it is always possible to deallocate
> memory with any allocator of the same type as the one that created it.  The
> std::allocator class is an example of such an allocator.  With a stateful
> allocator, you must effectively keep a copy of the allocator that allocated
> a piece of memory around to deallocate it again.  This makes implementing
> STL-like containers harder, hence the get-out clause in 20.1.5/4.
>
>

What is the advantage of using such stateful allocators?

>> No, I don't want to do something like that. It's just that I'm not totally
>> satisfied with the STL exception safety rules,
>
> What problems are you having in particular?  Someone on this newsgroup might
> be able to help.

The problem that I had was that I was assuming that since nothing was
mentioned about constructors of allocators throwing, I was assuming that
that requirement was the same as std::allocator, and that was stopping me
from desinging the allocatior properly.

>
>
> [snip much of implementation details of this class:]
[snip]......

>>
>> Yes, but I would want to allow default construction. Nice idea if I want
>> to disallow default construction though! It will kind of solve the
>> problem, but in a very crude way, where, the user will *have* instantiate
>> an allocator, and pass it to the ctor.
>

"There's no reason not to make the default constructor do the allocation
rather than the custom constructor"

I didn't quite get you here......


> , it then means that allocator will work
> perfectly as required.  If, as you mentioned above, you don't want to assume
> stateful allocators work, then using a static impl class, or alternatively,
> making the members of the impl class static would make everything work
> exactly to letter of the Standard.
>
> Hope that helps.
>
> --
> Richard Smith
> ---
> [ 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                       ]


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: 11 Jul 2003 08:49:35 -0400
Raw View
On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:

Just another quick question: Are allocators allowed to be templated around
more that one template parameter?

I asked this because boost allocators are, so would that make then
standard compliant?

Also, with such a design, template template parameters would not work, or
would they?

Reagrds,
-Dhruv.
---
[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: 11 Jul 2003 08:50:30 -0400
Raw View
On Thu, 10 Jul 2003 04:40:40 +0000, Ron Natalie wrote:

[snip]......

Thanks (for the snipped stuff).


>  >
>  > A templated copy ctor that throws, not the normal copy ctor.
>
> There's no such thing as a templated copy constructor.

Thanks, I just found that out :-)


Regards,
-Dhruv.
---
[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: Sat, 12 Jul 2003 07:35:12 GMT
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message
news:pan.2003.07.10.18.11.38.216161@gmx.net...
> On Wed, 09 Jul 2003 19:32:56 -0400, Richard Smith wrote:

[17.4.3.6/2, bullet 3:]
> "if the operations on the type do not implement the semantics of the
> applicable Requirements subclause (20.1.5, 23.1, 24.1, 26.1). "
>
> What exactly do you mean by this?

Basically just that if the template argument is required to model the
concept of an Allocator, then it results in undefined behaviour if the
template argument is not a model of an Allocator.

> I have something similar, but it's given as 17.3.3.6:
> "
> 2 In particular, the effects are undefined in the following cases:
> [snip]......
> --for  types  used as template arguments when instantiating a template
>     component, if the operations on the type do not implement the seman-
>     tics   of   the   applicable  Requirements  subclause  (_lib.alloca-
>     tor.requirements_,     _lib.container.requirements_,     _lib.itera-
>     tor.requirements_, _lib.numeric.requirements_).
>
>   --if  any of these functions or operations throws an exception, unless
>     specifically allowed in the applicable Required behavior  paragraph.
> "

OK.  The actual Standard does not have a 17.3.3.6, but it appears to be an
older version of the same thing.  I guess that the clause about exceptions
has now been weakened to read

| if any replacement function or handler function or destructor
| operation throws an exception, unless specifically allowed in
| the applicable Required behavior paragraph.

Functions on allocators are not replacement function (which is a very
specific term meaning functions like operator new() that are defined in the
library but which may also be defined in code).  Nor is it a handler
function (again, a very specific term meaning functions such as those passed
to set_new_handler, set_terminate and set_unexpected).  The destructor rule
applies, but I don't think there's ever been any discussion about that one.

> However, to be truthful, I always used
> to call them templated copy constructors, now that I know, I'll call them
> templated constructors.

Conversion constructors is another term that is sometimes encountered.

> What is the advantage of using such stateful allocators?

You don't have to store the heap in static variables as you have.  You can
have multiple heaps for a given type.


> >> Yes, but I would want to allow default construction. Nice idea if I
want
> >> to disallow default construction though! It will kind of solve the
> >> problem, but in a very crude way, where, the user will *have*
instantiate
> >> an allocator, and pass it to the ctor.
> >
>
> "There's no reason not to make the default constructor do the allocation
> rather than the custom constructor"
>
> I didn't quite get you here......

I meant do something like

 class alloc_impl { ... };

 template <class T>
 class my_allocator {
   public:
     my_allocator() : pimpl( new alloc_impl ) {}

   private:
     boost::shared_ptr<alloc_impl> pimpl;
 };

--
Richard Smith



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: kuyper@wizard.net (James Kuyper)
Date: Sat, 12 Jul 2003 08:36:13 GMT
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message news:<pan.2003.07.10.18.19.19.500436@gmx.net>...
 > On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
 >
 > Just another quick question: Are allocators allowed to be templated around
 > more that one template parameter?

The standard doesn't specify the number of template parameters. You
can have as many or as few as you wish, so long as the requirements in
20.1.5 are met.

The standard doesn't even require one template parameter. When you
re-bind an allocator, the rebind has to work with arbitrary types, so
that requires at least one templated family of allocators. However, a
given allocator type might work only for one type, and have a rebind
member that connects it to a templeted allocator.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: rmaddox@isicns.com (Randy Maddox)
Date: 12 Jul 2003 09:22:32 -0400
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message news:<pan.2003.07.10.18.11.38.216161@gmx.net>...
> On Wed, 09 Jul 2003 19:32:56 -0400, Richard Smith wrote:
>
> [snip]......
>
> > Maybe your using a draft copy of the Standard?  If so, you really should buy
> > a real copy -- it's not expensive and contains the definitive answer to
> > (almost) all questions like this.
> >
>
> Yes, in fact, I have the 1996 draft copy.
>

No need to work with outdated material.  Just go to www.ansi.org and
download a .pdf copy of the current Standard for $18US.

Randy.
---
[ 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: Andy Sawyer <andys@despammed.com>
Date: 12 Jul 2003 09:23:19 -0400
Raw View
In article <pan.2003.07.10.18.19.19.500436@gmx.net>,
 on 11 Jul 2003 08:49:35 -0400,
 "Dhruv" <dhruvbird@gmx.net> wrote:

> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>
> Just another quick question: Are allocators allowed to be templated around
> more that one template parameter?

In the case of std::allocator, the answer is clearly no (due to the
template template parameter issue).
For other allocators, however, I see no reason why not - although making
rebind do the right thing might be interesting.

> Also, with such a design, template template parameters would not work, or
> would they?

It rather depends on what you mean...

Regards,
 Andy S.
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man
---
[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: 12 Jul 2003 09:24:06 -0400
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message
news:pan.2003.07.10.18.19.19.500436@gmx.net...
> On Tue, 08 Jul 2003 02:32:22 +0000, Dhruv wrote:
>
> Just another quick question: Are allocators allowed to be templated around
> more that one template parameter?

Absolutely.  There are requirements on the template parameters of the
allocator.  There isn't even a requirement that it be templated, though it's
hard to think how else it could be implemented.  Basically, as long as you
can make rebind<> work, you're fine.

> Also, with such a design, template template parameters would not work, or
> would they?

Not sure how you want to use template template parameters.

If you want to do something like

  template <class T, template <class> class Policy>
  class my_allocator;

this is fine.

If you want to do

  template <class T> class my_allocator;
  std::vector< int, my_allocator > v;

it is not OK.

--
Richard Smith
---
[ 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: kuyper@wizard.net (James Kuyper)
Date: 12 Jul 2003 09:24:52 -0400
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message news:<pan.2003.07.10.18.11.38.216161@gmx.net>...
> On Wed, 09 Jul 2003 19:32:56 -0400, Richard Smith wrote:
...
> > Maybe your using a draft copy of the Standard?  If so, you really should buy
> > a real copy -- it's not expensive and contains the definitive answer to
> > (almost) all questions like this.
> >
>
> Yes, in fact, I have the 1996 draft copy.

Get the real standard. There are LOTS of difference between that draft
and the final version.

...
> > A stateful allocator (I don't think the Standard uses this term, but it is
> > used commonly elsewhere) is one that can have internal state.  The STL is
> > not required to support such allocators (there is a get-out clause in
> > 20.1.5/4), but implementations are "encouraged" to do so and increasingly
> > many do.  With a stateless allocator, it is always possible to deallocate
> > memory with any allocator of the same type as the one that created it.  The
> > std::allocator class is an example of such an allocator.  With a stateful
> > allocator, you must effectively keep a copy of the allocator that allocated
> > a piece of memory around to deallocate it again.  This makes implementing
> > STL-like containers harder, hence the get-out clause in 20.1.5/4.
> >
> >
>
> What is the advantage of using such stateful allocators?

On simple kind of stateful allocator uses a new, distinct memory pool
each time a new instance of the allocator is created, and shares that
pool with every instance created by copy construction, copy
assignment, and conversion. Instances that use different memory pools
are inequivalent, because they don't have access to each other's
memory pools.

...
> The problem that I had was that I was assuming that since nothing was
> mentioned about constructors of allocators throwing, I was assuming that
> that requirement was the same as std::allocator, and that was stopping me
> from desinging the allocatior properly.

Just read section 20.1.5; don't infer any additional requirements just
because they apply to the default allocator.
---
[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: 08 Jul 03 02:32:22 GMT
Raw View
On Fri, 04 Jul 2003 13:41:41 -0400, Richard Smith wrote:

 > "Dhruv" <dhruvbird@gmx.net> wrote in message
 > news:cf18e89.0306201003.521b0a1c@posting.google.com...
 >
 >> Yes, but the thing is that I have a link allocator (for single
 >> objects), and it does allocate in the constructor, and since I'm
 >> organizing the nodes as a list, this technique helps me a lot (to have
 >> a node already during construction). However, even then I'm just
 >> allocating space for a single node in the ctor, but that call to
 >> malloc may even fail, and failure to indicate that would lead to
 >> incorrect results later on.
 >
 > I can't see a requirement in the Standard for allocators' constructors or
 > copy constructors not to throw.

20.4.1
allocator() throw();
       allocator(const allocator&) throw();
       template <class U> allocator(const allocator<U>&) throw();
      ~allocator() throw();

Of course, this is for std::allocator<>()

 > Table 32 only states that deallocate
 > mustn't throw.

Where is Table 32?



 > This suggests to me that everything else can throw an
 > exception.  This is in keeping with 17.4.3.6/2 which says that operations
 > may throw unless otherwise specified, which talks about requirements of
 > template arguments.

I have only upto 17.3.4.8, where it says:
3 Any of the functions defined in the C++ Standard library that  do  not
   have   an  exception-specification  may  throw  implementation-defined
   exceptions.33)  An  implementation may strengthen this implicit excep-
   tion-specification by adding an explicit one.34)

Is this what you are talking about?

 > (Allocators are typically used as template arguments.)
 > Perhaps you're thinking of the requirement that std::allocator's default and
 > copy constructors do not throw?
 >

Yes.
I'm assuming that whatever holds true for std::allocator<> should hold
true for all other allocators, so that the user can have some sort of
guarantee that whatever allocator he/she uses, will have some predefined
guarantees about not throwing stuff, or throwing only in the allocate
function. Is the assumption justified?



 > In particular, I would say that if your default constructor needs to
 > allocate memory and fails, it certainly should indicate this by throwing an
 > exception.

Even I was thinking the same.

 > I'm less convinced about a copy constructor that throws --

A templated copy ctor that throws, not the normal copy ctor.

 > allocators probably should have handle rather than value semantics and so
 > would hold onto their internals using something like boost::shared_ptr.  If
 > you really need a copy constructor that throws, make sure you provide an
 > overload / specialisation of std::swap that does not throw.
 >
 > Finally, if your STL properly supports stateful allocators (they are not
 > required to: see 20.1.5/4),

Ok, so these implementation defined allocators are called stateful
allocators?


 > and you are prepared to tie yourself to such
 > STLs, you could make a default constructed allocator always fail to
 > allocate, and provide a custom constructor that correctly initialises the
 > object.  You would then need to pass a correctly constructed allocator into
 > STL containers' constructors:
 >

No, I don't want to do something like that. It's just that I'm not totally
satisfied with the STL exception safety rules, and as it is I'm having a
terrible time using exceptions the correct way. :-)


 >   namespace details {
 >     class my_allocator_impl {
 >      public:
 >       void* do_allocate( size_t bytes );
 >      // ...
 >     };
 >   }
 >
 >   template <class T>
 >   class my_allocator {
 >    public:
 >     my_allocator() {}
 >     my_allocator(/* some parameter */)
 >      : pimpl( new details::my_allocator_impl(/*...*/) {}
 >
 >     T* allocate(size_t n, void* hint = 0) {
 >       if (pimpl)
 >         return static_cast<T*>
 >          ( pimpl->do_allocate(n * sizeof(T)) );
 >       throw bad_alloc();
 >     }
 >
 >    private:
 >     boost::shared_ptr<details::my_allocator_impl> pimpl;
 >   };
 >
 > Something like this also allows more code to be moved out-of-line, reducing
 > dependencies.
 >


Yes, but I would want to allow default construction. Nice idea if I want
to disallow default construction though! It will kind of solve the
problem, but in a very crude way, where, the user will *have* instantiate
an allocator, and pass it to the ctor.


Regards,
-Dhruv.




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: kuyper@wizard.net (James Kuyper)
Date: 9 Jul 2003 19:31:50 -0400
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message news:<pan.2003.07.07.06.28.49.881813@gmx.net>...
> On Fri, 04 Jul 2003 13:41:41 -0400, Richard Smith wrote:
...
>  > I can't see a requirement in the Standard for allocators' constructors or
>  > copy constructors not to throw.
>
> 20.4.1
> allocator() throw();
>        allocator(const allocator&) throw();
>        template <class U> allocator(const allocator<U>&) throw();
>       ~allocator() throw();
>
> Of course, this is for std::allocator<>()

Exactly. It is NOT a requirement on the allocators in general.

>  > Table 32 only states that deallocate
>  > mustn't throw.
>
> Where is Table 32?

Section 20.1.5, page 356.

>  > This suggests to me that everything else can throw an
>  > exception.  This is in keeping with 17.4.3.6/2 which says that operations
>  > may throw unless otherwise specified, which talks about requirements of
>  > template arguments.
>
> I have only upto 17.3.4.8, where it says:

What do you mean by that? Does your copy of the standard have a break
in it somewhere between 17.3.4.8 and 17.4.3.6? If so, it's not the
final version of the standard.

> 3 Any of the functions defined in the C++ Standard library that  do  not
>    have   an  exception-specification  may  throw  implementation-defined
>    exceptions.33)  An  implementation may strengthen this implicit excep-
>    tion-specification by adding an explicit one.34)
>
> Is this what you are talking about?

No, he's referring to 17.4.3.6/2, as specified, on page 323. It says,
in part, "Operations on such types can report a failure by throwing an
exception unless otherwise specified."

...
> I'm assuming that whatever holds true for std::allocator<> should hold
> true for all other allocators, ...

Bad assumption. The default allocator is a very special case, with
many features that are not required of allocators in general.

> ... so that the user can have some sort of
> guarantee that whatever allocator he/she uses, will have some predefined
> guarantees about not throwing stuff, or throwing only in the allocate
> function. Is the assumption justified?

No. The only assumptions a user is allowed to make about general
allocators are those specified in table 20.1.5.

>  > allocators probably should have handle rather than value semantics and so
>  > would hold onto their internals using something like boost::shared_ptr.  If
>  > you really need a copy constructor that throws, make sure you provide an
>  > overload / specialisation of std::swap that does not throw.
>  >
>  > Finally, if your STL properly supports stateful allocators (they are not
>  > required to: see 20.1.5/4),
>
> Ok, so these implementation defined allocators are called stateful
> allocators?

Those particular allocators are stateful allocators, but it has
nothing to do with whether or not they are implementation-defined.
Section 20.1.5/4 lists two assumptions an implementation of a standard
library template is allowed to make about allocators (but which it is
encouraged to NOT make). A stateful allocator violates the first of
those optional assumptions: that all instances of a given allocator
type are equivalent. That means that code which uses a stateful
allocator type has to be careful about which instance it uses for
which purpose. Per table 32, you can safely use one instance of an
allocator to deallocate memory allocated by a different instance, only
if they compare equal.
---
[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: 9 Jul 2003 19:32:56 -0400
Raw View
"Dhruv" wrote:
>
> On Fri, 04 Jul 2003 13:41:41 -0400, Richard Smith wrote:
>
>  > I can't see a requirement in the Standard for allocators' constructors
or
>  > copy constructors not to throw.
>
> 20.4.1
>  allocator() throw();
>  allocator(const allocator&) throw();
>  template <class U> allocator(const allocator<U>&) throw();
> ~allocator() throw();
>
> Of course, this is for std::allocator<>()

Precisely.  What I said was that I couldn't see a requirement for allocators
in general (i.e. the Allocator concept) not to throw on default construction
or copying.  You are trying to write a new allocator, i.e. something that
models that Allocator concept without being std::allocator, and so this is
irrelevant.  Hence why I said ...

| Perhaps you're thinking of the requirement that std::allocator's default
| and copy constructors do not throw?

... in my previous email.

>  > Table 32 only states that deallocate mustn't throw.
>
> Where is Table 32?

On page 356 of the ISO Standard, in section 20.1.5,
[lib.allocator.requirements], "Allocator requirements".

>
>
>  > This suggests to me that everything else can throw an
>  > exception.  This is in keeping with 17.4.3.6/2 which says that
operations
>  > may throw unless otherwise specified, which talks about requirements of
>  > template arguments.
>
> I have only upto 17.3.4.8,

Maybe your using a draft copy of the Standard?  If so, you really should buy
a real copy -- it's not expensive and contains the definitive answer to
(almost) all questions like this.

> where it says:
> 3 Any of the functions defined in the C++ Standard library that  do  not
>    have   an  exception-specification  may  throw  implementation-defined
>    exceptions.33)  An  implementation may strengthen this implicit excep-
>    tion-specification by adding an explicit one.34)
>
> Is this what you are talking about?

No, I'm talking about the third bullet point paragraph 2 of 17.4.3.6,
[lib.res.on.functions], "Other functions":

| In particular, the effects are undefined in the following
| cases: [...]
|
|  * for types used as template arguments when instantiating
|    a template component, if the operations on the type do
|    not implement the semantics of the applicable Requirements
|    subclause (20.1.5, 23.1, 24.1, 26.1). Operations on such
|    types can report a failure by throwing an exception unless
|    otherwise specified.

This is sections talks about operations on user-supplied template arguments,
17.3.4.8 talks about functions defined in the Standard Library, i.e. things
like std::allocator<>'s copy constructor.

> I'm assuming that whatever holds true for std::allocator<> should hold
> true for all other allocators, so that the user can have some sort of
> guarantee that whatever allocator he/she uses, will have some predefined
> guarantees about not throwing stuff, or throwing only in the allocate
> function. Is the assumption justified?

Not entirely.  There are two separate things here: the concept of an
Allocator.  This a generic concept which defines what a general-purpose
allocator must do.  This is defined in section 20.1.5 of the Standard, and
in particular in Table 32.  Matt Austern's book, "Generic Programming and
the STL" covers this idea in section 9.4, which I find more conveniently
than the Standard.

The second thing is the std::allocator class template.  An instantiation of
this template is an example of the Allocator concept. (It is usual to say
std::allocator<T> models the Allocator concept.  You'll notice it is usual
to capitalise concepts to avoid confusion with their names.)  This means
that all of the expressions required by the Allocator concept must be legal,
and that they must have the prescribed semantics.  For example, if a is an
instance of an allocator, and n is a size_t[*], it must be legal to write

  a.allocate(n);

and this function must return a pointer[*] to memory to hold n objects of
the value_type of the allocator.  Otherwise it must throw.

  [*]  Actually, I'm glossing over some minor details with these
       point, but they're not relevant here.

In particular, all the Standard says about copying and default constructing
Allocators, is that you must be able to do so.  It doesn't say that they
mustn't throw, and hence by 17.4.3.6/2 they are allowed to.

>  > I'm less convinced about a copy constructor that throws --
>
> A templated copy ctor that throws, not the normal copy ctor.

A quick point on terminology:  a templated constructor can never be a copy
constructor.  [See footnote 106, to 12.8/2.]  Thus in the following example,
the class implicitly generates a copy-constructor.

  template <class T> class my_alloc {
   public:
    template <class U> my_alloc( const my_alloc<U>& other );
  };

Personally, I don't think that the copy or conversion (template)
constructors for an Allocator should throw.  This is not a requirement made
by the Standard, merely a rule-of-thumb I've found through experience. The
reason is that many operations within STL containers, etc. copy and
sometimes convert allocators very frequently, and so this should be very
efficient.  If you're doing something that can throw, the chances are it is
something relatively inefficient (e.g. allocating memory, etc.), hence my
suggestion to use a reference counted implementation class.

>  > Finally, if your STL properly supports stateful allocators (they are
not
>  > required to: see 20.1.5/4),
>
> Ok, so these implementation defined allocators are called stateful
> allocators?

A stateful allocator (I don't think the Standard uses this term, but it is
used commonly elsewhere) is one that can have internal state.  The STL is
not required to support such allocators (there is a get-out clause in
20.1.5/4), but implementations are "encouraged" to do so and increasingly
many do.  With a stateless allocator, it is always possible to deallocate
memory with any allocator of the same type as the one that created it.  The
std::allocator class is an example of such an allocator.  With a stateful
allocator, you must effectively keep a copy of the allocator that allocated
a piece of memory around to deallocate it again.  This makes implementing
STL-like containers harder, hence the get-out clause in 20.1.5/4.


> No, I don't want to do something like that. It's just that I'm not totally
> satisfied with the STL exception safety rules,

What problems are you having in particular?  Someone on this newsgroup might
be able to help.


[snip much of implementation details of this class:]

>  >   template <class T>
>  >   class my_allocator {
>  >    public:
>  >     my_allocator() {}
>  >     my_allocator(/* some parameter */)
>  >      : pimpl( new details::my_allocator_impl(/*...*/) {}
>  >
>  >    private:
>  >     boost::shared_ptr<details::my_allocator_impl> pimpl;
>  >   };
>
>
> Yes, but I would want to allow default construction. Nice idea if I want
> to disallow default construction though! It will kind of solve the
> problem, but in a very crude way, where, the user will *have* instantiate
> an allocator, and pass it to the ctor.

There's no reason not to make the default constructor do the allocation
rather than the custom constructor, it then means that allocator will work
perfectly as required.  If, as you mentioned above, you don't want to assume
stateful allocators work, then using a static impl class, or alternatively,
making the members of the impl class static would make everything work
exactly to letter of the Standard.

Hope that helps.

--
Richard Smith
---
[ 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: "Ron Natalie" <ron@sensor.com>
Date: Thu, 10 Jul 2003 04:40:40 GMT
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message news:pan.2003.07.07.06.28.49.881813@gmx.net...

 >  > I can't see a requirement in the Standard for allocators' constructors or
 >  > copy constructors not to throw.
 >
 > 20.4.1
 > allocator() throw();
 >        allocator(const allocator&) throw();
 >        template <class U> allocator(const allocator<U>&) throw();
 >       ~allocator() throw();
 >
 > Of course, this is for std::allocator<>()
 >

That only says the default allocator will not throw.   It doesn't say that any
allocator used is required not to throw.

 >  > Table 32 only states that deallocate
 >  > mustn't throw.
 >
 > Where is Table 32?

20.1.5 Allocator Requirements.

 >>
 > I have only upto 17.3.4.8, where it says:
 > 3 Any of the functions defined in the C++ Standard library that  do  not
 >    have   an  exception-specification  may  throw  implementation-defined
 >    exceptions.33)  An  implementation may strengthen this implicit excep-
 >    tion-specification by adding an explicit one.34)
 >
 > Is this what you are talking about?

That and the absence of any requrirement in 20.1.5.


 > Yes.
 > I'm assuming that whatever holds true for std::allocator<> should hold
 > true for all other allocators, so that the user can have some sort of
 > guarantee that whatever allocator he/she uses,

Bad assumption.   The general allocator requirements are in 20.1.5.  The
fact that the std allocator is better behaved than required doesn't mean
anything.

 >
 > A templated copy ctor that throws, not the normal copy ctor.

There's no such thing as a templated copy constructor.
                       ]



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: dhruvbird@gmx.net ("Dhruv")
Date: Thu, 10 Jul 2003 21:55:23 +0000 (UTC)
Raw View
On Tue, 24 Jun 2003 03:39:30 +0000, Andy Sawyer wrote:

> In article <slrnbetqa5.1ds.do-not-spam-ben.hutchings@tin.bwsint.com>,
>  on Fri, 20 Jun 2003 19:36:08 +0000 (UTC),
>  do-not-spam-ben.hutchings@businesswebsoftware.com (Ben Hutchings) wrote:
>
>> In article <cf18e89.0306160249.609cb0ba@posting.google.com>,
>> Dhruv wrote:
>>
>> > Also, I want to confirm that new[0] allocates space for 1
>> > object, or allocates 1 byte? or is this is just an implementation
>> > defined value?
>> >
>> > However, the standard indicates something different altogether: I'm
>> > assuming that the para below applies to the operator new and operator
>> > new[] functions, and not to new class_type, pr new[] class_type.
>> > i.e. the new operator, not operator new. That's why everything is
>> > fine.
>> >
>> > 3.7.3.1p2:
>> > "If  the  size  of  the  space
>> >   requested  is  zero,  the  value  returned shall not be a null
>> >   pointer value (_conv.ptr_).  The results of dereferencing a pointer
>> >   returned as a request for zero size are undefined.8)"
>>
>> I interpret this as meaning that the return value is unspecified,
>> beyond being non-null.  On a byte-oriented flat-memory machine, the
>> return value for an allocation of 0 bytes could always be, say,
>> (T*)(-1).  ::operator delete and ::operator delete[] would then treat
>> this as a special case.
>
> This has now been clarified, with the following wording:
>
> ,----[ 3.7.3.1/p2 ]
> | Even if the size of the space requested is zero, the request can
> | fail. If the request succeeds, the value returned shall be a
> | non-null pointer value (4.10) p0 different from any previously
> | returned value p1, unless that value p1 was subsequently passed to
> | an operator delete.
> `----
>
> So the "(T*)(-1)" implementation would no longer conform.
>

Thanks for the clarification, though I have a few questions:

So, this means that now, new int[0] can fail? So, what, will it throw
std::bad_alloc()?

Also, is the 2nd part trying to say this:?

Suppose you have something like this:

int *pint = new int[0];
delete pint;
pint = new int[0];

Meaning that pint now can (could) hold the same value that it held before
the call to delete?


>>
>> > "8)  The intent is to have operator new() implementable by calling
>> >   malloc() or calloc(), so the rules are substantially the same.  C++
>> >   differs  from C in requiring a zero request to return a non-null
>> >   pointer."
>>
>> malloc(0) can either return a null pointer or behave like ::operator
>> new(0); this is implementation-defined.  On an implementation with the
>> former behaviour, ::operator new and ::operator new[] can call
>> malloc(1) when asked for 0 bytes.
>
> This implementation, on the other hand, would conform.
>


Regards,
-Dhruv.






---
[ 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: "Dhruv" <dhruvbird@gmx.net>
Date: Thu, 3 Jul 2003 14:13:43 +0000 (UTC)
Raw View
On Wed, 25 Jun 2003 15:13:27 +0000, Ross Ridge wrote:

>
> kanze@gabi-soft.fr wrote:
>> Not being able to allocate the memory in an allocator is not an illegal
>>operation.  Normally, too, it doesn't occur in the constructor of the
>>allocator, but when the allocate function is called.  And the standard
>>requires the allocate function to throw bad_alloc if it cannot allocate
>>the memory.
>
> Dhruv <dhruvbird@gmx.net> wrote:
>>Yes, but the thing is that I have a link allocator (for single
>>objects), and it does allocate in the constructor, and since I'm
>>organizing the nodes as a list, this technique helps me a lot (to have
>>a node already during construction). However, even then I'm just
>>allocating space for a single node in the ctor, but that call to
>>malloc may even fail, and failure to indicate that would lead to
>>incorrect results later on.
>
> Defer allocation of the single node until the first call to allocate().
>

If I do that, then for every call to allocate(), I will have to check for
the head pointer being valid, and that would be a terrible price to pay.
Even if I defer the throwing of the exception in the allocate function,
then also, I'll have to do some sort of error checking every time it is
called. Also, it has occured to me that I could have 2 versions of the
allocate function, as in make allocate actually call a funtion through a
pointer. In the constructor, set the pointer to the initialization
function, and when the initialization function is called, it sets the
pointer to the actual function (for normal operation). Then again, it will
involve indirection of some sort, and will slow down the thing again.

-Dhruv.









      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Richard Smith" <richard@ex-parrot.com>
Date: 4 Jul 2003 13:41:41 -0400
Raw View
"Dhruv" <dhruvbird@gmx.net> wrote in message
news:cf18e89.0306201003.521b0a1c@posting.google.com...

> Yes, but the thing is that I have a link allocator (for single
> objects), and it does allocate in the constructor, and since I'm
> organizing the nodes as a list, this technique helps me a lot (to have
> a node already during construction). However, even then I'm just
> allocating space for a single node in the ctor, but that call to
> malloc may even fail, and failure to indicate that would lead to
> incorrect results later on.

I can't see a requirement in the Standard for allocators' constructors or
copy constructors not to throw.  Table 32 only states that deallocate
mustn't throw.  This suggests to me that everything else can throw an
exception.  This is in keeping with 17.4.3.6/2 which says that operations
may throw unless otherwise specified, which talks about requirements of
template arguments. (Allocators are typically used as template arguments.)
Perhaps you're thinking of the requirement that std::allocator's default and
copy constructors do not throw?

In particular, I would say that if your default constructor needs to
allocate memory and fails, it certainly should indicate this by throwing an
exception.  I'm less convinced about a copy constructor that throws --
allocators probably should have handle rather than value semantics and so
would hold onto their internals using something like boost::shared_ptr.  If
you really need a copy constructor that throws, make sure you provide an
overload / specialisation of std::swap that does not throw.

Finally, if your STL properly supports stateful allocators (they are not
required to: see 20.1.5/4), and you are prepared to tie yourself to such
STLs, you could make a default constructed allocator always fail to
allocate, and provide a custom constructor that correctly initialises the
object.  You would then need to pass a correctly constructed allocator into
STL containers' constructors:

  namespace details {
    class my_allocator_impl {
     public:
      void* do_allocate( size_t bytes );
     // ...
    };
  }

  template <class T>
  class my_allocator {
   public:
    my_allocator() {}
    my_allocator(/* some parameter */)
     : pimpl( new details::my_allocator_impl(/*...*/) {}

    T* allocate(size_t n, void* hint = 0) {
      if (pimpl)
        return static_cast<T*>
         ( pimpl->do_allocate(n * sizeof(T)) );
      throw bad_alloc();
    }

   private:
    boost::shared_ptr<details::my_allocator_impl> pimpl;
  };

Something like this also allows more code to be moved out-of-line, reducing
dependencies.

--
Richard Smith
---
[ 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: rridge@csclub.uwaterloo.ca (Ross Ridge)
Date: Fri, 4 Jul 2003 20:53:32 +0000 (UTC)
Raw View
Ross Ridge wrote:
> Defer allocation of the single node until the first call to allocate().

Dhruv <dhruvbird@gmx.net> wrote:
>If I do that, then for every call to allocate(), I will have to check for
>the head pointer being valid, and that would be a terrible price to pay.

I have a hard time imagining how this could be significant compared
to the cost of doing the allocate.

>Even if I defer the throwing of the exception in the allocate function,
>then also, I'll have to do some sort of error checking every time it is
>called.

Your allocate function is already required by the standard to throw an
exception if it can't allocate the requested memory.  You have to do
this checking anyways, so this doesn't change anything.

      Ross Ridge

--
 l/  //   Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/
 db  //

---
[ 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: dhruvbird@gmx.net ("Dhruv")
Date: Mon, 7 Jul 2003 08:07:28 +0000 (UTC)
Raw View
On Fri, 04 Jul 2003 20:53:32 +0000, Ross Ridge wrote:

> Ross Ridge wrote:
>> Defer allocation of the single node until the first call to allocate().
>
> Dhruv <dhruvbird@gmx.net> wrote:
>>If I do that, then for every call to allocate(), I will have to check for
>>the head pointer being valid, and that would be a terrible price to pay.
>
> I have a hard time imagining how this could be significant compared
> to the cost of doing the allocate.
>

I'll have to try it out then :-) I'll add the code, as you said, and time
it again.


>>Even if I defer the throwing of the exception in the allocate function,
>>then also, I'll have to do some sort of error checking every time it is
>>called.
>
> Your allocate function is already required by the standard to throw an
> exception if it can't allocate the requested memory.  You have to do
> this checking anyways, so this doesn't change anything.
>

I think you have got me wrong here. I think I'll post a link to the code
here: http://www.geocities.com/dhruvbird/nstl0.2.zip

The file to be looking out for is list_alloc.hpp


Regards,
-Dhruv.

---
[ 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: andys@despammed.com (Andy Sawyer)
Date: Tue, 24 Jun 2003 03:39:30 +0000 (UTC)
Raw View
In article <slrnbetqa5.1ds.do-not-spam-ben.hutchings@tin.bwsint.com>,
 on Fri, 20 Jun 2003 19:36:08 +0000 (UTC),
 do-not-spam-ben.hutchings@businesswebsoftware.com (Ben Hutchings) wrote:

> In article <cf18e89.0306160249.609cb0ba@posting.google.com>,
> Dhruv wrote:
>
> > Also, I want to confirm that new[0] allocates space for 1
> > object, or allocates 1 byte? or is this is just an implementation
> > defined value?
> >
> > However, the standard indicates something different altogether: I'm
> > assuming that the para below applies to the operator new and operator
> > new[] functions, and not to new class_type, pr new[] class_type.
> > i.e. the new operator, not operator new. That's why everything is
> > fine.
> >
> > 3.7.3.1p2:
> > "If  the  size  of  the  space
> >   requested  is  zero,  the  value  returned shall not be a null
> >   pointer value (_conv.ptr_).  The results of dereferencing a pointer
> >   returned as a request for zero size are undefined.8)"
>
> I interpret this as meaning that the return value is unspecified,
> beyond being non-null.  On a byte-oriented flat-memory machine, the
> return value for an allocation of 0 bytes could always be, say,
> (T*)(-1).  ::operator delete and ::operator delete[] would then treat
> this as a special case.

This has now been clarified, with the following wording:

,----[ 3.7.3.1/p2 ]
| Even if the size of the space requested is zero, the request can
| fail. If the request succeeds, the value returned shall be a
| non-null pointer value (4.10) p0 different from any previously
| returned value p1, unless that value p1 was subsequently passed to
| an operator delete.
`----

So the "(T*)(-1)" implementation would no longer conform.

>
> > "8)  The intent is to have operator new() implementable by calling
> >   malloc() or calloc(), so the rules are substantially the same.  C++
> >   differs  from C in requiring a zero request to return a non-null
> >   pointer."
>
> malloc(0) can either return a null pointer or behave like ::operator
> new(0); this is implementation-defined.  On an implementation with the
> former behaviour, ::operator new and ::operator new[] can call
> malloc(1) when asked for 0 bytes.

This implementation, on the other hand, would conform.

Regards,
 Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man

---
[ 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: dhruvbird@gmx.net (Dhruv)
Date: Tue, 24 Jun 2003 03:41:38 +0000 (UTC)
Raw View
do-not-spam-ben.hutchings@businesswebsoftware.com (Ben Hutchings) wrote in message news:<slrnbetqa5.1ds.do-not-spam-ben.hutchings@tin.bwsint.com>...
> In article <cf18e89.0306160249.609cb0ba@posting.google.com>,

> It's not generally bad to throw in constructors, but in this case
> you'll have to.  Alternatively give your allocator class a static
> initialisation function that must be called before any allocators
> are constructed.
>
> > Also, deallocate(ptr, 0) is UB,
>
> Are you reading a draft of the standard?  The real standard and the
> final draft both say for deallocate():
>
>    "Requires:  p shall be a pointer value obtained from allocate().
>     n shall equal the value passed as the first argument to the
>     invocation of allocate which returned p."
>
Yes, so that would mean that passing 'n' to be != the value passed to
allocate on the invovcation of allocate would be undefined behaviour.

> > but nothing is written about
> > allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
> > acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
> > also UB......
>
> It's implicitly defined:
>
>    "Notes: Uses ::operator new(size_t) (18.4.1)."
>
Full quote: "Note:
    the storage is obtained by calling ::operator new(size_t), but it
is
    unspecified when or how often this function is called.  The  use
of
    hint is unspecified, but intended as an aid to locality if an
imple-
    mentation so desires."

It need not call it every time allocate() is called.

> > Also, I want to confirm that new[0] allocates space for 1
> > object, or allocates 1 byte? or is this is just an implementation
> > defined value?
> >
> > However, the standard indicates something different altogether: I'm
> > assuming that the para below applies to the operator new and operator
> > new[] functions, and not to new class_type, pr new[] class_type.
> > i.e. the new operator, not operator new. That's why everything is
> > fine.
> >
> > 3.7.3.1p2:
> > "If  the  size  of  the  space
> >   requested  is  zero,  the  value  returned shall not be a null
> >   pointer value (_conv.ptr_).  The results of dereferencing a pointer
> >   returned as a request for zero size are undefined.8)"
>
> I interpret this as meaning that the return value is unspecified,
> beyond being non-null.  On a byte-oriented flat-memory machine, the
> return value for an allocation of 0 bytes could always be, say,
> (T*)(-1).  ::operator delete and ::operator delete[] would then treat
> this as a special case.
>
> > "8)  The intent is to have operator new() implementable by calling
> >   malloc() or calloc(), so the rules are substantially the same.  C++
> >   differs  from C in requiring a zero request to return a non-null
> >   pointer."
>
> malloc(0) can either return a null pointer or behave like ::operator
> new(0); this is implementation-defined.  On an implementation with the
> former behaviour, ::operator new and ::operator new[] can call
> malloc(1) when asked for 0 bytes.
>
> ---
> [ 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                       ]

---
[ 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: rridge@csclub.uwaterloo.ca (Ross Ridge)
Date: Wed, 25 Jun 2003 15:13:27 +0000 (UTC)
Raw View
kanze@gabi-soft.fr wrote:
> Not being able to allocate the memory in an allocator is not an illegal
>operation.  Normally, too, it doesn't occur in the constructor of the
>allocator, but when the allocate function is called.  And the standard
>requires the allocate function to throw bad_alloc if it cannot allocate
>the memory.

Dhruv <dhruvbird@gmx.net> wrote:
>Yes, but the thing is that I have a link allocator (for single
>objects), and it does allocate in the constructor, and since I'm
>organizing the nodes as a list, this technique helps me a lot (to have
>a node already during construction). However, even then I'm just
>allocating space for a single node in the ctor, but that call to
>malloc may even fail, and failure to indicate that would lead to
>incorrect results later on.

Defer allocation of the single node until the first call to allocate().

       Ross Ridge

--
 l/  //   Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/
 db  //



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: tom_usenet@hotmail.com (tom_usenet)
Date: Thu, 19 Jun 2003 20:40:41 +0000 (UTC)
Raw View
On 17 Jun 03 04:26:12 GMT, dhruvbird@gmx.net (Dhruv) wrote:

>I wanted to know that if the stdandard allocators are not allowed to
>throw() during their construction/copy construction, but what if the
>allocator performs an illegal operation while begin constructed, and
>wants to signal that? How to do that. I know it's generally bad to
>throw in constructors,

Where did you hear that? Constructors are the one place you *have* to
throw to indicate an error.

but then it's always better to throw() as soon
>as an error is encountered, so that the user can debug exactly the
>affected area, and find out what is going on.

Exceptions aren't intended for debugging, but for error handling. Use
"assert" for debugging, since when an exception is throw, the stack is
unwound and the throw site is lost.

 An alternative to this
>would be to throw in allocate(), but then that would delay the throw,
>and the user would never know that the ctor is the actual culprit.
>
>Also, deallocate(ptr, 0) is UB, but nothing is written about
>allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
>acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
>also UB......

Actually, there is a TC about it:

http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#199

Apparently it is well defined, but the return value is unspecified
(except that I think you can pass it to deallocate, so I suppose that
means it can't be null).

>
>Also, I want to confirm that new[0] allocates space for 1
>object, or allocates 1 byte? or is this is just an implementation
>defined value?

It doesn't give you a dereferenceable pointer, but it does give you a
unique pointer. How much memory is actually allocated depends on the
implementation, but it will probably be 4 bytes (the 4 bytes preceding
the pointer you are gived) + allocator overhead.

See 5.3.4/7.

>
>However, the standard indicates something different altogether: I'm
>assuming that the para below applies to the operator new and operator
>new[] functions, and not to new class_type, pr new[] class_type.
>i.e. the new operator, not operator new. That's why everything is
>fine.

Yes, it applies to allocation functions like ::operator new, not to
new-expressions like "new int(0)".

>
>3.7.3.1p2:
>"If  the  size  of  the  space
>  requested  is  zero,  the  value  returned shall not be a null
pointer
>  value (_conv.ptr_).  The results of dereferencing a  pointer
returned
>  as a request for zero size are undefined.8)"
>
>"8)  The intent is to have operator new() implementable by calling mal-
>  loc() or calloc(), so the rules are substantially the same.  C++
dif-
>  fers  from C in requiring a zero request to return a non-null
>pointer."
>

new expressions are covered in 5.3.4.

Tom

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Fri, 20 Jun 2003 14:58:25 +0000 (UTC)
Raw View
dhruvbird@gmx.net (Dhruv) wrote in message
news:<cf18e89.0306171942.2baec05f@posting.google.com>...
> kanze@gabi-soft.fr wrote in message
> news:<d6652001.0306170214.74216d5b@posting.google.com>...
> > dhruvbird@gmx.net (Dhruv) wrote in message
> > news:<cf18e89.0306160249.609cb0ba@posting.google.com>...

> > > I wanted to know that if the stdandard allocators are not allowed
> > > to throw() during their construction/copy construction, but what
> > > if the allocator performs an illegal operation while begin
> > > constructed, and wants to signal that?

> > By means of a core dump or an assertion failure.

> Ok, so I could use assert here.

> I was in some doubt, because the constructor(s) of the object indulge
> in dynamic memory allocation, using malloc/new, and if new fails, or
> malloc==0, then I'd need to signal a failure to the effect that there
> is not enough memory available to complete the construction, so I'd
> want to throw bad_alloc or something to that effect.

> Would that be a reasonable step to take in such a case?

Not being able to allocate the memory in an allocator is not an illegal
operation.  Normally, too, it doesn't occur in the constructor of the
allocator, but when the allocate function is called.  And the standard
requires the allocate function to throw bad_alloc if it cannot allocate
the memory.

--
James Kanze             GABI Software             mailto:kanze@gabi-soft.fr
Conseils en informatique orient   e objet/
                           Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T   l. : +33 (0)1 30 23 45 16



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: do-not-spam-ben.hutchings@businesswebsoftware.com (Ben Hutchings)
Date: Fri, 20 Jun 2003 19:36:08 +0000 (UTC)
Raw View
In article <cf18e89.0306160249.609cb0ba@posting.google.com>,
Dhruv wrote:
> I wanted to know that if the stdandard allocators are not allowed to
> throw() during their construction/copy construction, but what if the
> allocator performs an illegal operation while begin constructed, and
> wants to signal that?

Don't do that.  An "illegal operation" in the Windows sense is one of
the many possible behaviours that come under the heading of "undefined
behaviour".

> How to do that. I know it's generally bad to throw in constructors,
> but then it's always better to throw() as soon as an error is
> encountered, so that the user can debug exactly the affected area,
> and find out what is going on. An alternative to this would be to
> throw in allocate(), but then that would delay the throw, and the
> user would never know that the ctor is the actual culprit.

It's not generally bad to throw in constructors, but in this case
you'll have to.  Alternatively give your allocator class a static
initialisation function that must be called before any allocators
are constructed.

> Also, deallocate(ptr, 0) is UB,

Are you reading a draft of the standard?  The real standard and the
final draft both say for deallocate():

   "Requires:  p shall be a pointer value obtained from allocate().
    n shall equal the value passed as the first argument to the
    invocation of allocate which returned p."

> but nothing is written about
> allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
> acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
> also UB......

It's implicitly defined:

   "Notes: Uses ::operator new(size_t) (18.4.1)."

> Also, I want to confirm that new[0] allocates space for 1
> object, or allocates 1 byte? or is this is just an implementation
> defined value?
>
> However, the standard indicates something different altogether: I'm
> assuming that the para below applies to the operator new and operator
> new[] functions, and not to new class_type, pr new[] class_type.
> i.e. the new operator, not operator new. That's why everything is
> fine.
>
> 3.7.3.1p2:
> "If  the  size  of  the  space
>   requested  is  zero,  the  value  returned shall not be a null
>   pointer value (_conv.ptr_).  The results of dereferencing a pointer
>   returned as a request for zero size are undefined.8)"

I interpret this as meaning that the return value is unspecified,
beyond being non-null.  On a byte-oriented flat-memory machine, the
return value for an allocation of 0 bytes could always be, say,
(T*)(-1).  ::operator delete and ::operator delete[] would then treat
this as a special case.

> "8)  The intent is to have operator new() implementable by calling
>   malloc() or calloc(), so the rules are substantially the same.  C++
>   differs  from C in requiring a zero request to return a non-null
>   pointer."

malloc(0) can either return a null pointer or behave like ::operator
new(0); this is implementation-defined.  On an implementation with the
former behaviour, ::operator new and ::operator new[] can call
malloc(1) when asked for 0 bytes.

---
[ 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: dhruvbird@gmx.net (Dhruv)
Date: Fri, 20 Jun 2003 23:06:52 +0000 (UTC)
Raw View
kanze@gabi-soft.fr wrote in message
news:<d6652001.0306190745.6bbd72d8@posting.google.com>...
> dhruvbird@gmx.net (Dhruv) wrote in message
> news:<cf18e89.0306171942.2baec05f@posting.google.com>...
> > kanze@gabi-soft.fr wrote in message
> > news:<d6652001.0306170214.74216d5b@posting.google.com>...
> > > dhruvbird@gmx.net (Dhruv) wrote in message
> > > news:<cf18e89.0306160249.609cb0ba@posting.google.com>...
>
> > > > I wanted to know that if the stdandard allocators are not
allowed
> > > > to throw() during their construction/copy construction, but what
> > > > if the allocator performs an illegal operation while begin
> > > > constructed, and wants to signal that?
>
> > > By means of a core dump or an assertion failure.
>
> > Ok, so I could use assert here.
>
> > I was in some doubt, because the constructor(s) of the object
indulge
> > in dynamic memory allocation, using malloc/new, and if new fails, or
> > malloc==0, then I'd need to signal a failure to the effect that
there
> > is not enough memory available to complete the construction, so I'd
> > want to throw bad_alloc or something to that effect.
>
> > Would that be a reasonable step to take in such a case?
>
> Not being able to allocate the memory in an allocator is not an
illegal
> operation.  Normally, too, it doesn't occur in the constructor of the
> allocator, but when the allocate function is called.  And the standard
> requires the allocate function to throw bad_alloc if it cannot
allocate
> the memory.
>

Yes, but the thing is that I have a link allocator (for single
objects), and it does allocate in the constructor, and since I'm
organizing the nodes as a list, this technique helps me a lot (to have
a node already during construction). However, even then I'm just
allocating space for a single node in the ctor, but that call to
malloc may even fail, and failure to indicate that would lead to
incorrect results later on.

I can send you the code if you wish.

I do have a few doubts about the design though.

-Dhruv.



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: dhruvbird@gmx.net (Dhruv)
Date: 17 Jun 03 04:26:12 GMT
Raw View
I wanted to know that if the stdandard allocators are not allowed to
throw() during their construction/copy construction, but what if the
allocator performs an illegal operation while begin constructed, and
wants to signal that? How to do that. I know it's generally bad to
throw in constructors, but then it's always better to throw() as soon
as an error is encountered, so that the user can debug exactly the
affected area, and find out what is going on. An alternative to this
would be to throw in allocate(), but then that would delay the throw,
and the user would never know that the ctor is the actual culprit.

Also, deallocate(ptr, 0) is UB, but nothing is written about
allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
also UB......

Also, I want to confirm that new[0] allocates space for 1
object, or allocates 1 byte? or is this is just an implementation
defined value?

However, the standard indicates something different altogether: I'm
assuming that the para below applies to the operator new and operator
new[] functions, and not to new class_type, pr new[] class_type.
i.e. the new operator, not operator new. That's why everything is
fine.

3.7.3.1p2:
"If  the  size  of  the  space
  requested  is  zero,  the  value  returned shall not be a null pointer
  value (_conv.ptr_).  The results of dereferencing a  pointer  returned
  as a request for zero size are undefined.8)"

"8)  The intent is to have operator new() implementable by calling mal-
  loc() or calloc(), so the rules are substantially the same.  C++  dif-
  fers  from C in requiring a zero request to return a non-null
pointer."


-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: 17 Jun 2003 18:44:00 -0400
Raw View
dhruvbird@gmx.net (Dhruv) wrote in message
news:<cf18e89.0306160249.609cb0ba@posting.google.com>...

> I wanted to know that if the stdandard allocators are not allowed to
> throw() during their construction/copy construction, but what if the
> allocator performs an illegal operation while begin constructed, and
> wants to signal that?

By means of a core dump or an assertion failure.

Why should the copy constructor of an allocator execute an illegal
operation?  (For that matter, why should any code execute an illegal
operation?)  If code executes an illegal operation, it is normally a
sign that there is an error in the code, and you almost certainly don't
want an exception in that case.

> How to do that. I know it's generally bad to throw in constructors,

Constructors are probably the case where exceptions are most justified.
If it's bad to throw in constructors, it is bad to throw anywhere.

> but then it's always better to throw() as soon as an error is
> encountered, so that the user can debug exactly the affected area, and
> find out what is going on.

I think you misunderstand what throw does.  If you throw an exception,
and it is caught, the user can't debug anything.  If you want to debug,
you want a crash -- under Unix, you get a core dump, which you can
exploit by means of a debugger, and under Windows, it depends on the
configuration, but I think you can drop into the debugger immediately.
An exception says that you are going to handle the error in your own
code, and that it is NOT a programming error.

> An alternative to this would be to throw in allocate(), but then that
> would delay the throw, and the user would never know that the ctor is
> the actual culprit.

> Also, deallocate(ptr, 0) is UB, but nothing is written about
> allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
> acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
> also UB......

> Also, I want to confirm that new[0] allocates space for 1 object, or
> allocates 1 byte?

Not at all.  It allocates space (at a unique address) for 0 objects.

> or is this is just an implementation defined value?

Nothing implementation defined about it.  new T[0] must return a unique
pointer which can be copied and compared, but dereferencing this pointer
is undefined behavior.  (Logically, it is a pointer to one past the end
of the array, since the start of an array of 0 elements is already one
past the end.)

> However, the standard indicates something different altogether: I'm
> assuming that the para below applies to the operator new and operator
> new[] functions, and not to new class_type, pr new[] class_type.
> i.e. the new operator, not operator new.  That's why everything is
> fine.

> 3.7.3.1p2:
> "If the size of the space requested is zero, the value returned shall
> not be a null pointer value (_conv.ptr_).  The results of
> dereferencing a pointer returned as a request for zero size are
> undefined.8)"

> "8)  The intent is to have operator new() implementable by calling mal-
>   loc() or calloc(), so the rules are substantially the same.  C++  dif-
>   fers  from C in requiring a zero request to return a non-null
> pointer."

It applies to ALL allocation functions, including any that you might
provide.

--
James Kanze             GABI Software             mailto:kanze@gabi-soft.fr
Conseils en informatique orient   e objet/
                           Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T   l. : +33 (0)1 30 23 45 16
---
[ 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: David Abrahams <dave@boost-consulting.com>
Date: 17 Jun 2003 18:44:37 -0400
Raw View
dhruvbird@gmx.net (Dhruv) writes:

> I wanted to know that if the stdandard allocators are not allowed to
> throw() during their construction/copy construction, but what if the
> allocator performs an illegal operation while begin constructed, and
> wants to signal that? How to do that.

Illegal operations are... illegal.

If you want to signal that an illegal operation happened, it's usually
best to dump core so that a debugger gets a clear view of the program
state.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ 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: dhruvbird@gmx.net (Dhruv)
Date: 18 Jun 03 17:53:55 GMT
Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0306170214.74216d5b@posting.google.com>...
> dhruvbird@gmx.net (Dhruv) wrote in message
> news:<cf18e89.0306160249.609cb0ba@posting.google.com>...
>
> > I wanted to know that if the stdandard allocators are not allowed to
> > throw() during their construction/copy construction, but what if the
> > allocator performs an illegal operation while begin constructed, and
> > wants to signal that?
>
> By means of a core dump or an assertion failure.
>

Ok, so I could use assert here.

I was in some doubt, because the constructor(s) of the object indulge
in dynamic memory allocation, using malloc/new, and if new fails, or
malloc==0, then I'd need to signal a failure to the effect that there
is not enough memory available to complete the construction, so I'd
want to throw bad_alloc or something to that effect.

Would that be a reasonable step to take in such a case?


> Why should the copy constructor of an allocator execute an illegal
> operation?  (For that matter, why should any code execute an illegal
> operation?)  If code executes an illegal operation, it is normally a
> sign that there is an error in the code, and you almost certainly don't
> want an exception in that case.
>
> > How to do that. I know it's generally bad to throw in constructors,
>
> Constructors are probably the case where exceptions are most justified.
> If it's bad to throw in constructors, it is bad to throw anywhere.
>
> > but then it's always better to throw() as soon as an error is
> > encountered, so that the user can debug exactly the affected area, and
> > find out what is going on.
>
> I think you misunderstand what throw does.  If you throw an exception,
> and it is caught, the user can't debug anything.  If you want to debug,
> you want a crash -- under Unix, you get a core dump, which you can
> exploit by means of a debugger, and under Windows, it depends on the
> configuration, but I think you can drop into the debugger immediately.
> An exception says that you are going to handle the error in your own
> code, and that it is NOT a programming error.
>
> > An alternative to this would be to throw in allocate(), but then that
> > would delay the throw, and the user would never know that the ctor is
> > the actual culprit.
>
> > Also, deallocate(ptr, 0) is UB, but nothing is written about
> > allocate(0). Knowing that new[0] amounts to new[1], and delete[](0) is
> > acceptable, and amounts to a NO-OP, I'm assuming that allocate(0) is
> > also UB......
>
> > Also, I want to confirm that new[0] allocates space for 1 object, or
> > allocates 1 byte?
>
> Not at all.  It allocates space (at a unique address) for 0 objects.
>

Thanks :-)

> > or is this is just an implementation defined value?
>
> Nothing implementation defined about it.  new T[0] must return a unique
> pointer which can be copied and compared, but dereferencing this pointer
> is undefined behavior.  (Logically, it is a pointer to one past the end
> of the array, since the start of an array of 0 elements is already one
> past the end.)
>
> > However, the standard indicates something different altogether: I'm
> > assuming that the para below applies to the operator new and operator
> > new[] functions, and not to new class_type, pr new[] class_type.
> > i.e. the new operator, not operator new.  That's why everything is
> > fine.
>
> > 3.7.3.1p2:
> > "If the size of the space requested is zero, the value returned shall
> > not be a null pointer value (_conv.ptr_).  The results of
> > dereferencing a pointer returned as a request for zero size are
> > undefined.8)"
>
> > "8)  The intent is to have operator new() implementable by calling mal-
> >   loc() or calloc(), so the rules are substantially the same.  C++  dif-
> >   fers  from C in requiring a zero request to return a non-null
> > pointer."
>
> It applies to ALL allocation functions, including any that you might
> provide.
>

Thanks again :-)


-Dhruv.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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                       ]