Topic: restrictions on types that can be put in STL containers
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Wed, 25 Jul 2001 11:20:41 GMT Raw View
"Matthias Benkmann" <mbenkmann@gmx.de> wrote in message
news:3b5dbbd7.3250060@news.cis.dfn.de...
> On Tue, 24 Jul 2001 17:17:54 GMT, "Anthony Williams"
> <anthwil@nortelnetworks.com> wrote:
>
> >"Matthias Benkmann" <mbenkmann@gmx.de> wrote in message
> >news:3b5c8f97.24766423@news.cis.dfn.de...
[SNIP]
> >> When is the moment of instantiation? Is the following portable
> >>
> >> class formula
> >> {
> >> vector<formula>* subformulas;
> >> }
> >
> >Having read the quoted section, I am convinced that any mention of
> >vector<incomplete_type> is illegal.
[SNIP]
>
> This is not an issue in the above. A vector<formula>* is always a
> pointer and so the size of class formula is well-defined regardless of
> the implementation of vector<>. It's like having a formula* member in
> the class formula or a pointer to a forward declared class. I know
> that in theory an implentation could have different types of pointers
> but this would only apply to pointers to basic types or different
> pointers based on storage class. Having different pointers for
> different classes would make pointers to forward declared classes
> impossible, so no compiler will ever implement it.
>
> So unless a compiler wants to instantiate vector<formula> while it is
> still parsing class formula (which is absolutely unneccessary because
> no information from vector<> is needed) the above will work. I have
> tested it on my compiler. Instead of vector<> I used a container that
> has a non-pointer member of the contained type. As expected
> container<formula> did not work. However container<formula>* works.
> Now there are 3 questions
>
> a) does the standard specify the earliest point where a template is
> instantiated?
Yes
> b) if the answer to a) is yes, then is this point within the class
> declaration in the above example or after
14.7.1.p1
"Unless a class template specialization has been explicitly instantiated
(14.7.2) or explicitly specialized (14.7.3), the class template
specialization is implicitly instantiated when the specialization is
referenced in a context that requires a completely defined object type or
when the completeness of the class type affects the semantics of the
program."
So I think my earlier statement about "any mention of
vector<some_incomplete_type>" being illegal was a bit overkill.
In your example, the instantiation comes after, as the completeness of the
vector<> does not affect the program.
> Anyway, I'm not out of ideas, yet. Now the following *has* to be
> standards conforming:
>
> class forward;
>
> class formula
> {
> forward* subformulas;
> };
>
> class forward:public vector<formula>{};
Agreed.
> Now class formula is certainly well-defined because pointers to
> forward declared classes are allowed and when class forward is
> declared class formula is not incomplete anymore.
> The only thing I'm a bit worried about is deriving from
> vector<formula>. I know that the STL classes are not meant to be
> derived from, mostly because their members are not virtual. But I am
> not adding any new members so there can't be anything wrong with class
> forward, right?
Correct
> Or does the standard say that deriving from an STL container is
> undefined behaviour per se? If so, does that mean that the STL
> implementation code is actually not supposed to be standards
> conforming C++ code? I ask because I can not see any standards
> conforming way to write a C++ class that can not be derived from.
Deriving from an STL container is not recommended, but legal.
It is possible by use of virtual inheritance and friendship to prevent
derivation.
class MyClass;
class MyClassFinalBase
{
private:
friend class MyClass;
MyClassFinalBase(){}
MyClassFinalBase(const MyClassFinalBase&){}
};
class MyClass: virtual MyClassFinalBase
{};
class Derived: MyClass // Error
{};
The constructor for derived must call the constructor for MyClassFinalBase,
as it is a virtual base. However, all the constructors are private, so this
is not permitted. Therefore Derived cannot have a legal constructor, and
must be illformed.
Unfortunately, MyClassFinalBase cannot be a template (for use with the
"Self-parameterized base class" idiom), because template parameters cannot
be friends.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Wed, 25 Jul 2001 17:39:33 GMT Raw View
"P.J. Plauger" <pjp@dinkumware.com> wrote in message
news:3b5cbf71$0$15642@wodc7nh0.news.uu.net...
> "Sebastian Bohmann" <sbohmann@chello.at> wrote in message
news:7k%67.47166$Ob3.1215999@news.chello.at...
>
> > > In many implementations of vector, the class only contains pointers to
the
> > > contained type, as the managed memory is elsewhere to enable dynamic
> > > resizing, so this is OK. If the library writer uses something akin to
the
> > > small-string optimisation (the small vector optimisation?) where
enough
> > > memory is allocated in the class itself for a few of the contained
items,
> > > then the class will require the sizeof() (at least) of the template
> > > parameter, which requires it to be a complete type.
> >
> > Doesn't the standard prohibit dengerous things like such optimisation in
STL
> > containers?
>
> Yes, because all elements of the sequence controlled by the container must
> be allocated by the allocator.
21.3p8 says
"All other constructors for these container types take an Allocator&
argument (20.1.5), an allocator whose value type is the same as the
container's value type. A copy of this argument is used for any memory
allocation performed, by these constructors and by all member functions,
during the lifetime of each container object."
However, I don't see that this statement requires all controlled elements to
be in memory allocated using the allocator - if no memory is allocated by
the container (because it is all within the container object itself) then
the allocator is not used. e.g.
template<typename T,typename Allocator>
class vector : Allocator
{
private:
T* beg,end,finish; // normal storage pointers
unsigned char data[5000]; // The Allocator is only used if the required
memory exceeds 5000 bytes.
// ...
};
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Matthew Austern <austern@research.att.com>
Date: Mon, 23 Jul 2001 19:55:14 GMT Raw View
mbenkmann@gmx.de (Matthias Benkmann) writes:
> Is the following construct allowed by the standard?
>
> class formula
> {
> vector<formula> subformulas;
> }
>
> More precisely, does a standard-compliant STL implementation guarantee
> that incomplete types work with containers?
No. The standard forbids instantiating an STL container (or any other
standard library template) with an incomplete type.
17.4.3.6, paragraph 2: "the effects are undefined ... if an incomplete
type (3.9) is used as a template argument when instantiating a
template component."
I agree that this features would be useful, but the committee didn't
know how to make it work in general. We believe that in some cases
allowing incomplete types would be technically impossible because of
requirements that already exist elsewhere in the standard.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Sebastian Bohmann" <sbohmann@chello.at>
Date: Mon, 23 Jul 2001 20:02:58 GMT Raw View
> In many implementations of vector, the class only contains pointers to the
> contained type, as the managed memory is elsewhere to enable dynamic
> resizing, so this is OK. If the library writer uses something akin to the
> small-string optimisation (the small vector optimisation?) where enough
> memory is allocated in the class itself for a few of the contained items,
> then the class will require the sizeof() (at least) of the template
> parameter, which requires it to be a complete type.
Doesn't the standard prohibit dengerous things like such optimisation in STL
containers?
After all, imagine a vector<very_big_class> , whereas very_big_class'
size was 1/5th of the available memory and vector<> allocated space for 20
objects...
not very flexible.
But on the other hand, more intelligent optimisation could be attemped
by -trying- to
reserve unallocated memory -dynamically-. And using the -sizeof- operator
inside vector<>
under these circumstances (inside an incomplete class) should at least be
theoretically possible.
Now comes my question:
Is it? I mean, according to the standard.
Thank yers,
-- Sebastian Bohmann
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Mon, 23 Jul 2001 21:35:37 GMT Raw View
On Mon, 23 Jul 2001 19:55:14 GMT, Matthew Austern
<austern@research.att.com> wrote:
>mbenkmann@gmx.de (Matthias Benkmann) writes:
>
>> Is the following construct allowed by the standard?
>>
>> class formula
>> {
>> vector<formula> subformulas;
>> }
>>
>> More precisely, does a standard-compliant STL implementation guarantee
>> that incomplete types work with containers?
>
>No. The standard forbids instantiating an STL container (or any other
>standard library template) with an incomplete type.
>
>17.4.3.6, paragraph 2: "the effects are undefined ... if an incomplete
>type (3.9) is used as a template argument when instantiating a
>template component."
Okay. Now what exactly does "instantiating a template component" mean.
When is the moment of instantiation? Is the following portable
class formula
{
vector<formula>* subformulas;
}
Here, knowing the complete type should not be necessary because I just
have a pointer. Note that this is vector<formula>* NOT
vector<formula*>. The latter will work of course but is tedious to
maintain and has the usual memory leak potential.
MSB
----
By the way:
Vacuum cleaners suck!
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Tue, 24 Jul 2001 09:46:48 GMT Raw View
"Sebastian Bohmann" <sbohmann@chello.at> wrote in message
news:7k%67.47166$Ob3.1215999@news.chello.at...
>
> > In many implementations of vector, the class only contains pointers to
the
> > contained type, as the managed memory is elsewhere to enable dynamic
> > resizing, so this is OK. If the library writer uses something akin to
the
> > small-string optimisation (the small vector optimisation?) where enough
> > memory is allocated in the class itself for a few of the contained
items,
> > then the class will require the sizeof() (at least) of the template
> > parameter, which requires it to be a complete type.
>
>
> Doesn't the standard prohibit dengerous things like such optimisation in
STL
> containers?
> After all, imagine a vector<very_big_class> , whereas
very_big_class'
> size was 1/5th of the available memory and vector<> allocated space for 20
> objects...
> not very flexible.
> But on the other hand, more intelligent optimisation could be attemped
> by -trying- to
> reserve unallocated memory -dynamically-. And using the -sizeof- operator
> inside vector<>
> under these circumstances (inside an incomplete class) should at least be
> theoretically possible.
> Now comes my question:
>
> Is it? I mean, according to the standard.
Having read the section of the standard highlighted by Matt Austern
(17.4.3.6), I stand corrected. Incomplete types are not permitted to be used
with std::vector<> (possibly because the effects of such use depend on the
implementation of the standard library templates as I described), which
means any use of sizeof() within the vector class definition is legal.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "P.J. Plauger" <pjp@dinkumware.com>
Date: Tue, 24 Jul 2001 17:00:38 GMT Raw View
"Sebastian Bohmann" <sbohmann@chello.at> wrote in message news:7k%67.47166$Ob3.1215999@news.chello.at...
> > In many implementations of vector, the class only contains pointers to the
> > contained type, as the managed memory is elsewhere to enable dynamic
> > resizing, so this is OK. If the library writer uses something akin to the
> > small-string optimisation (the small vector optimisation?) where enough
> > memory is allocated in the class itself for a few of the contained items,
> > then the class will require the sizeof() (at least) of the template
> > parameter, which requires it to be a complete type.
>
> Doesn't the standard prohibit dengerous things like such optimisation in STL
> containers?
Yes, because all elements of the sequence controlled by the container must
be allocated by the allocator.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.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.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Tue, 24 Jul 2001 17:17:54 GMT Raw View
"Matthias Benkmann" <mbenkmann@gmx.de> wrote in message
news:3b5c8f97.24766423@news.cis.dfn.de...
> On Mon, 23 Jul 2001 19:55:14 GMT, Matthew Austern
> <austern@research.att.com> wrote:
>
> >> More precisely, does a standard-compliant STL implementation guarantee
> >> that incomplete types work with containers?
> >
> >No. The standard forbids instantiating an STL container (or any other
> >standard library template) with an incomplete type.
> >
> >17.4.3.6, paragraph 2: "the effects are undefined ... if an incomplete
> >type (3.9) is used as a template argument when instantiating a
> >template component."
>
> Okay. Now what exactly does "instantiating a template component" mean.
> When is the moment of instantiation? Is the following portable
>
> class formula
> {
> vector<formula>* subformulas;
> }
Having read the quoted section, I am convinced that any mention of
vector<incomplete_type> is illegal. Having thought about it, I can see a
strong argument for this - permitting instantation on incomplete types
limits the implementation of standard library templates to only use pointers
and references to the template argument within their class definition, which
is quite a restriction. The other possibilities (cf undefined behaviour) are
to make it unspecified behaviour (not much use to anyone - you can't ever
rely on it) or implementation defined behaviour (which makes user code too
dependent on implementation details, and thus non-portable).
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Sebastian Bohmann" <sbohmann@chello.at>
Date: Tue, 24 Jul 2001 18:43:31 GMT Raw View
yes... the ALLOCATOR.
I completely forgot about that.
But from this point of view it should be PERFECTLY legal to state this...
class X {
vector<X> v_;
};
as the size and semantics of X would be perfectly clear.
....should it not?
(as to should or not to should is sometimes hard to determine, just like
here)
-- Sebastian Bohmann
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Tue, 24 Jul 2001 18:51:21 GMT Raw View
On Tue, 24 Jul 2001 17:17:54 GMT, "Anthony Williams"
<anthwil@nortelnetworks.com> wrote:
>"Matthias Benkmann" <mbenkmann@gmx.de> wrote in message
>news:3b5c8f97.24766423@news.cis.dfn.de...
>> On Mon, 23 Jul 2001 19:55:14 GMT, Matthew Austern
>> <austern@research.att.com> wrote:
>>
>> >> More precisely, does a standard-compliant STL implementation guarantee
>> >> that incomplete types work with containers?
>> >
>> >No. The standard forbids instantiating an STL container (or any other
>> >standard library template) with an incomplete type.
>> >
>> >17.4.3.6, paragraph 2: "the effects are undefined ... if an incomplete
>> >type (3.9) is used as a template argument when instantiating a
>> >template component."
>>
>> Okay. Now what exactly does "instantiating a template component" mean.
>> When is the moment of instantiation? Is the following portable
>>
>> class formula
>> {
>> vector<formula>* subformulas;
>> }
>
>Having read the quoted section, I am convinced that any mention of
>vector<incomplete_type> is illegal. Having thought about it, I can see a
>strong argument for this - permitting instantation on incomplete types
>limits the implementation of standard library templates to only use pointers
>and references to the template argument within their class definition, which
>is quite a restriction. The other possibilities (cf undefined behaviour) are
>to make it unspecified behaviour (not much use to anyone - you can't ever
>rely on it) or implementation defined behaviour (which makes user code too
>dependent on implementation details, and thus non-portable).
This is not an issue in the above. A vector<formula>* is always a
pointer and so the size of class formula is well-defined regardless of
the implementation of vector<>. It's like having a formula* member in
the class formula or a pointer to a forward declared class. I know
that in theory an implentation could have different types of pointers
but this would only apply to pointers to basic types or different
pointers based on storage class. Having different pointers for
different classes would make pointers to forward declared classes
impossible, so no compiler will ever implement it.
So unless a compiler wants to instantiate vector<formula> while it is
still parsing class formula (which is absolutely unneccessary because
no information from vector<> is needed) the above will work. I have
tested it on my compiler. Instead of vector<> I used a container that
has a non-pointer member of the contained type. As expected
container<formula> did not work. However container<formula>* works.
Now there are 3 questions
a) does the standard specify the earliest point where a template is
instantiated?
b) if the answer to a) is yes, then is this point within the class
declaration in the above example or after
c) does anyone with more technical knowledge about implementing
templates in a compiler know whether any real-world compiler would
ever want to instantiate vector<formula> on encountering a
vector<formula>* in a class declaration. I think this would be
inconsistent with normal treatment of pointers in class declarations.
After all, pointer_to_incomplete is a very common phenomenon.
Anyway, I'm not out of ideas, yet. Now the following *has* to be
standards conforming:
class forward;
class formula
{
forward* subformulas;
};
class forward:public vector<formula>{};
Now class formula is certainly well-defined because pointers to
forward declared classes are allowed and when class forward is
declared class formula is not incomplete anymore.
The only thing I'm a bit worried about is deriving from
vector<formula>. I know that the STL classes are not meant to be
derived from, mostly because their members are not virtual. But I am
not adding any new members so there can't be anything wrong with class
forward, right?
Or does the standard say that deriving from an STL container is
undefined behaviour per se? If so, does that mean that the STL
implementation code is actually not supposed to be standards
conforming C++ code? I ask because I can not see any standards
conforming way to write a C++ class that can not be derived from.
MSB
----
By the way:
Vacuum cleaners suck!
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: mbenkmann@gmx.de (Matthias Benkmann)
Date: Mon, 23 Jul 2001 12:00:44 GMT Raw View
Is the following construct allowed by the standard?
class formula
{
vector<formula> subformulas;
}
More precisely, does a standard-compliant STL implementation guarantee
that incomplete types work with containers? I think this is very
desirable as it allows one to avoid error-prone manual fiddling with
pointers when building recursive data structures like the above (which
btw works on my compiler).
MSB
----
By the way:
Vacuum cleaners suck!
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Mon, 23 Jul 2001 19:14:08 GMT Raw View
"Matthias Benkmann" <mbenkmann@gmx.de> wrote in message
news:3b5be47f.4652869@news.cis.dfn.de...
> Is the following construct allowed by the standard?
>
> class formula
> {
> vector<formula> subformulas;
> }
>
> More precisely, does a standard-compliant STL implementation guarantee
> that incomplete types work with containers? I think this is very
> desirable as it allows one to avoid error-prone manual fiddling with
> pointers when building recursive data structures like the above (which
> btw works on my compiler).
It depends on the implementation, so there is no guarantee. If the
implementation requires that the template parameter be a complete type, in
order for the container to be complete, then incomplete types will not work.
If the implementation only depends on pointers and references to the type
for the container class definition then there is no problem, as these things
can be used for incomplete types.
In many implementations of vector, the class only contains pointers to the
contained type, as the managed memory is elsewhere to enable dynamic
resizing, so this is OK. If the library writer uses something akin to the
small-string optimisation (the small vector optimisation?) where enough
memory is allocated in the class itself for a few of the contained items,
then the class will require the sizeof() (at least) of the template
parameter, which requires it to be a complete type.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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.research.att.com/~austern/csc/faq.html ]