Topic: Is the 'as if' rule appliable here? (A reawakening)
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Tue, 3 Apr 2007 17:23:17 CST Raw View
James Kanze schrieb:
> C++98 said that the implementation used "string"; I don't think
> you can detect if it doesn't, so as-if covers it.
Good point, I have overlooked this subtle difference!
And as I see in that moment, even the 14882:2003
document uses the notion of "string".
> The current draft says that the implementation used
> basic_string< charT, traits >, which means that it uses
> a traits class which I wrote; that might provide a means.
Do you mean that it provides means to detect a
difference?
> Note that this change (between C++98 and the current draft)
> could also conceivably break code. Again, however, it would
> require a really perverse traits class, and I'll bet that in
> practice, no real code is affected.
That is true, although I always have accepted such breaks,
if these where due to defect reports. OK, one reasonable
argument against such a break is, that it would *not* break
an already defective code in this case.
> > From my view-point a well-written replacement using e.g.
> > a C array of fixed length would be sufficient to provide this
> > guarantee. The tricky point might be the situation of too
> > little free store,
>
> You don't need any free store, since you can allocate on stack:
> charT buffer[ N ] ;
Yes, of course. My reasoning was vice-versa: If I replace
an earlier (basic_)string-based implementation by one
which uses a stack-based buffer, this is (theoretically)
detectable via the memory allocator. And in situations of
too little memory the older impl. would have thrown, the
new one maybe not. Yes, these are pure lawyer thoughts,
but I try to position myself in an implementor, that
tries to guess it's chances of probably crazy code
breaks. This may sound silly (and most users would
probably applaud the new code), but I read once, that
during at least one MS Window's version change the
MS crew provided special handlers for some selected
games to work on the newer version, although the
reason of failing to do so (in the newer version) were
based on programming errors in the game. These were
programming errors's which the old OS version accepted
w/o any OS exception, but were already defective in
the old version..
> > E.g. can we interpret
[..]
> > that every expression involving new/delete (in which hidden
> > way ever) *must* necessarily have observable side-effects
> > and that this means that we cannot replace them by
> > alternative options?
>
> That's the way I've always interpreted it. Particularly in that
> the standard, in some cases, takes pains to decouple the two,
> e.g. 20.6.1.1/6 "the storage is obtained by calling ::operator
> new(std::size_t), but it is unspecified when or how often this
> function is called." If an implementation had the right,
> generally, to skip dynamic allocation, then this sentence
> wouldn't be necessary.
Hmmh, I have understood this from the view-point of a
user of allocator. If I use the allocator::allocate function,
I explicitely *demand* this call and I'm willing to accept the
consequences. The additional information is provided,
because I might also provide ::operator new(std::size_t), in
the example you gave, and I could consider to write
disgustedly e-mails to my compiler vendor just because
not every invokation of allocate did also invoke my ::operator
new. After that I get a answer in a friendly tone, which
nicely explains me that this behaviour is granted by the
standard and that I should be happy to have such a
high-quality allocator implementation, which uses a very
intelligent and an internationally patented block allocator...
This way or the other, the system *will* aquire free store
from the OS via *my* operator new, but I don't know
exactly when.
But you are right: If I don't know, exactly *when* my
allocator is invoked, it will usually not be an easy task
for me to detect a given string instantiation. But, if
I also have the allocator in my hands... ;-)
> For the moment, I'd like to see a conforming program which could
> tell.
If *you* say that, I'm convinced - no kidding.
> Exceeding resource limitations is undefined behavior. (I forget
> where it says this in the standard, but someone showed it to me
> once.)
If you find it again - please write me an e-mail! (The address
is usable)
> I'm not sure about your example. Calling use_facet has no
> effect on any reference count. The reference count refers to
> the number of locale objects which contain the facet, and I'm
> willing to bet that with most implementations, you'll run out of
> memory long before you overflow. On the other hand, there's
> also no requirement with regards to how and where the
> implementation performs its reference counting. The fact that
> the "flag" you pass to the constructor is in fact a size_t which
> can take only two numeric values, rather than a bool, is very
> suggestive, but presumably, an implementation could maintain the
> reference counts on a simple signed char, and beg out on
> "resources exceeded" when it overflowed.
Grumpf, after rethinking, I also would categorize my example
as *very* artifical and *not* really convincing.
Greetings from Bremen,
Daniel
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "James Kanze" <james.kanze@gmail.com>
Date: Wed, 4 Apr 2007 08:49:00 CST Raw View
On Apr 4, 1:23 am, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> James Kanze schrieb:
> > C++98 said that the implementation used "string"; I don't think
> > you can detect if it doesn't, so as-if covers it.
> Good point, I have overlooked this subtle difference!
> And as I see in that moment, even the 14882:2003
> document uses the notion of "string".
> > The current draft says that the implementation used
> > basic_string< charT, traits >, which means that it uses
> > a traits class which I wrote; that might provide a means.
> Do you mean that it provides means to detect a
> difference?
Probably not, but maybe. Some code which you wrote is involved,
so potentially, you at least have a chance. But the standard
doesn't specify exactly how many calls to which traits functions
will occur for which basic_string operations, nor which
operations are actually used in the function in question, and of
course, there's nothing to prevent an implementation from using
the traits class above without using basic_string, either.
One possibility might be to specialize basic_string on a type
you defined, and instrument the specialization. The standard
says ( 17.4.3.1): "A program may explicitly instantiate any
templates in the standard library only if the declaration
depends on the name of a user-defined type of external linkage
and the instantiation meets the standard library requirements
for the original template." I'm not sure just how much leeway
that gives. Suppose your specialization of basic_string behaved
exactly like basic_string, except that you counted the numer of
times a constructor was invoked, and made that information
available. That would definitly result in an observable
difference if the implementation never used basic_string, but
I'm not sure that that still qualifies as "meets the standard
library requirements for the original template."
> > Note that this change (between C++98 and the current draft)
> > could also conceivably break code. Again, however, it would
> > require a really perverse traits class, and I'll bet that in
> > practice, no real code is affected.
> That is true, although I always have accepted such breaks,
> if these where due to defect reports. OK, one reasonable
> argument against such a break is, that it would *not* break
> an already defective code in this case.
> > > From my view-point a well-written replacement using e.g.
> > > a C array of fixed length would be sufficient to provide this
> > > guarantee. The tricky point might be the situation of too
> > > little free store,
> > You don't need any free store, since you can allocate on stack:
> > charT buffer[ N ] ;
> Yes, of course. My reasoning was vice-versa: If I replace
> an earlier (basic_)string-based implementation by one
> which uses a stack-based buffer, this is (theoretically)
> detectable via the memory allocator. And in situations of
> too little memory the older impl. would have thrown, the
> new one maybe not.
Except that you have no guarantees as to when the allocator may
be called. Suppose the library's implementation of basic_string
uses the small string optimization, with "small" being defined
as anything less that 100 KB. Suppose the standard allocator
gets memory in very big blocks, and only rarely goes to your
instrumented global allocator. Suppose on the other hand that
the implementation uses vector< charT >, instead of
basic_string< charT >? I don't think you can use the allocator
as an observable external behavior here.
> Yes, these are pure lawyer thoughts,
> but I try to position myself in an implementor, that
> tries to guess it's chances of probably crazy code
> breaks. This may sound silly (and most users would
> probably applaud the new code), but I read once, that
> during at least one MS Window's version change the
> MS crew provided special handlers for some selected
> games to work on the newer version, although the
> reason of failing to do so (in the newer version) were
> based on programming errors in the game. These were
> programming errors's which the old OS version accepted
> w/o any OS exception, but were already defective in
> the old version..
All major vendors do that. Proving to your customer that he
doesn't know what he is doing is not a particularly effective
way of increasing sales.
> > > E.g. can we interpret
> [..]
> > > that every expression involving new/delete (in which hidden
> > > way ever) *must* necessarily have observable side-effects
> > > and that this means that we cannot replace them by
> > > alternative options?
> > That's the way I've always interpreted it. Particularly in that
> > the standard, in some cases, takes pains to decouple the two,
> > e.g. 20.6.1.1/6 "the storage is obtained by calling ::operator
> > new(std::size_t), but it is unspecified when or how often this
> > function is called." If an implementation had the right,
> > generally, to skip dynamic allocation, then this sentence
> > wouldn't be necessary.
> Hmmh, I have understood this from the view-point of a user of
> allocator. If I use the allocator::allocate function, I
> explicitely *demand* this call and I'm willing to accept the
> consequences. The additional information is provided, because
> I might also provide ::operator new(std::size_t), in the
> example you gave, and I could consider to write disgustedly
> e-mails to my compiler vendor just because not every
> invokation of allocate did also invoke my ::operator new.
> After that I get a answer in a friendly tone, which nicely
> explains me that this behaviour is granted by the standard and
> that I should be happy to have such a high-quality allocator
> implementation, which uses a very intelligent and an
> internationally patented block allocator... This way or the
> other, the system *will* aquire free store from the OS via
> *my* operator new, but I don't know exactly when.
> But you are right: If I don't know, exactly *when* my
> allocator is invoked, it will usually not be an easy task
> for me to detect a given string instantiation. But, if
> I also have the allocator in my hands... ;-)
You don't. The default allocator is part of the standard
library, and specification for the operator says that it uses
basic_string<charT, traits> (and thus, the default allocator).
> > For the moment, I'd like to see a conforming program which could
> > tell.
> If *you* say that, I'm convinced - no kidding.
I've not tried. I'm not sure how to go about it, but I've also
seen no proof that it isn't possible.
A lot depends, too, on just how much latitude we do have in
implementing a traits class or a specialization of basic_string.
I'm not sure that the standard is really clear about this.
> > Exceeding resource limitations is undefined behavior. (I forget
> > where it says this in the standard, but someone showed it to me
> > once.)
> If you find it again - please write me an e-mail! (The address
> is usable)
1.4 Implementation compliance
[...]
-- If a program contains no violations of the rules in this
International Standard, a conforming implementation
shall, WITHIN ITS RESOURCE LIMITS, accept and correctly
execute that program.
Since the standard never says what the implementation should do
if the resource limits are exceeded, it's undefined behavior.
One obvious reason for this is that the standard doesn't want to
define behavior for cases like stack overflow.
Note that there are specific exceptions as well. The standard
does specify what happens if there is insufficient memory to
serve an operator new request, for example, so that is not
undefined behavior. In theory, at least. In practice, the
implementation will never try to do better than the OS, and if
the OS uses lazy page allocation (e.g. Linux, in its default
configuration), you will effectively get undefined behavior,
even if the standard says its not. And of course, the standard
makes no guarantees about time, so if the OS suspends your
process when it can't fulfill a memory request, and only resumes
it when the memory is available (like Windows, at least in some
configurations), it's fully conformant... and fully useless if
you're trying to create any sort of reliable system.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: gennaro.prota@yahoo.com (Gennaro Prota)
Date: Wed, 4 Apr 2007 13:47:08 GMT Raw View
On Tue, 3 Apr 2007 11:27:24 CST, James Kanze wrote:
>On Apr 3, 12:23 am, "Daniel Kr=FCgler" <daniel.krueg...@googlemail.com>
>wrote:
>> Gennaro Prota schrieb:
>
>> > Basically, I think that if a string is required then the extractor i=
s
>> > over-specified.
>
>> I agree, although I cannot surely decide whether the current
>> wordings demand that. This would lead us to the definition
>> and conformance against as-if again.
>
>C++98 said that the implementation used "string"; I don't think
>you can detect if it doesn't, so as-if covers it. The current
>draft says that the implementation used basic_string< charT,
>traits >, which means that it uses a traits class which I wrote;
>that might provide a means.
They had totally forgotten that the char-type was a generic CharT;
that's lib issue 303. In a stroke of modesty, I think my
implementation of dynamic_bitset's (new iostreams) extractor was the
first in the world to be pseudo-correct in that regard (I mean the
first implementation *of dynamic_bitset*, of course... there weren't
any others ;-)) And I say "*pseudo*-correct" because of the "known
consequence of the design choice" mentioned at the end of the lib
issue 303 discussion; were it for me, I'd have used narrow.
>Note that this change (between C++98 and the current draft)
>could also conceivably break code. Again, however, it would
>require a really perverse traits class, and I'll bet that in
>practice, no real code is affected.
>
>> > But, as you say too, one could use a built-in array, or another
>> > bitset object, and (what I meant to be) the main question --"is
>> > it ok to avoid using a string?"-- would remain.
>
>> From my view-point a well-written replacement using e.g.
>> a C array of fixed length would be sufficient to provide this
>> guarantee. The tricky point might be the situation of too
>> little free store,
>
>You don't need any free store, since you can allocate on stack:
> charT buffer[ N ] ;
Isn't that what both Daniel and me keep repeating?
>> where an bad_alloc is thrown. E.g. can we
>> interpret the note given in 1.9
>
>> "For instance, an actual implementation need not evaluate
>> part of an expression if it can deduce that its value is not
>> used and that ...
>
>> [...]
>
>For the moment, I'd like to see a conforming program which could
>tell.
Inventing which is a perfectly good way to waste software engineers'
energies. In the same amount of time I guess I can write 12
specifications of the extractor which don't require a string. The only
reason I haven't filed a defect report is that the committee has
probably better things to do than fixing this. And quite frankly,
reading the discussion around lib issue 434 is disheartening. Bitset
could win a prize for the most sloppily designed and specified (and
DR-ed) facility of the library (just see what section of the standard
its spec is in).
--=20
Gennaro Prota.
In search of passioned C++ developers? I'm available.
Breeze C++: https://sourceforge.net/projects/breeze/
(incomplete, preview state)
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Sat, 31 Mar 2007 17:07:37 CST Raw View
Gennaro Prota schrieb:
> On Thu, 29 Mar 2007 14:52:38 GMT, Alberto Ganesh Barbati wrote:
> >(notice that the number of binary digits produced is equal to the number
> >of bits specified in the template argument).
> >
> >The issue about performances is that operator<< is implemented by first
> >converting the number to a string and then outputting the string, thus
> >potentially incurring in a dynamic allocation.
>
> Better late than never.. I think I'll make another attempt at getting
> a reply for this:
>
> <http://google.com/group/comp.std.c++/msg/c2e71528fa98fa06>
I would like to divide this discussion into two seperate concerns:
1) Whether std::bitset could be implemented as described in
your much earlier posting in the sense of as-if.
2) General inconsistencies of the current standard concerning
transactionality of IO extractors.
ad 1) Modulo possible errors in the code (I haven't checked
so far), I don't think that the proposed and obviously more
performant implementation can be used as written as an
alternative which fulfills as-if rules. The problem is basically
related to (2) and can be simply expressed by recognizing
that the current standard words require a transactional
"strong guarantee" (relative to the target bitset, *not* to the
stream) for bitset's extractor, but your proposal does only
provide the "basic guarantee".
I don't think that any similar problems would occur, if vector<
charT> or a similar character buffer would be used instead of
basic_string<charT>, as you also asked for, because the
transactional behaviour relative to the bitset target would be
the same. IMO the performance differences between those
dynamic buffers would probably be marginally (e.g. both
vector and basic_string have a reserve function).
We could of-course use a buffer of static length, either a
temporary bitset tmp (and we would apply basically your
code with that one and thereby circumventing the described
transactional differences and also simplifying your exception
handler) or std::array<charT, N>. The usage of either array or
vector would require the need of additional implementation-
defined c'tors for bitset, so no real advantage (besides non-
free-store memory in case of std::array or even a C array)
exists compared to your sligthly changed implementation.
ad 2) While studying a currently new active issue regarding
complex IO extraction found at
http://www2.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#629
I realized that the standard library is rather inconsistent
relative to transactional behaviour of formatted IO extractions.
In the following my references belong to N2134:
1) By implication the IO extractions of the arithmetic
types+void* (27.6.1.2.2) seem to have the "strong guarantee"
relative to the target (*not* to the stream), see num_get
description 22.2.2.1/1:
"[..] If an error occurs, val is unchanged; otherwise it is set to
the resulting value."
(Btw: By studying the new special handlers for short and
int I found and reported a defect, because the as-if-code
fragments are invalid C++ and never set the obtained value)
2) basic_string is clearly described as having only the "basic
guarantee" (see 21.3.8.9/1):
"[..] After constructing a sentry object, if the sentry converts to
true, calls str.erase() and then extracts characters[..]"
3) bitset, as described in 23.3.5.3, has "strong guarantee".
4) complex, as described in 26.3.6/12-15, *seems* to provide
only the basic guarantee, at least nothing is said that requieres
that the original value remains unchanged in case of an error.
5) Random number engines, as described in table 98 of
section 26.4.1.3 provide the "strong guarantee":
"[..] If bad input is encountered, ensures that v's state is
unchanged by the operation[..]"
6) charT*/unsigned char*/signed char* (27.6.1.2.3/7-11) provide
the "basic guarantee".
7) basic_streambuf<charT,traits>* (27.6.1.2.3/14-16) provides
the "basic guarantee".
8) Random number distributions, as described in table 100
(26.4.1.5) provide "strong guarantee"
9) get_money as described in 27.6.4/3+4, provides by
implication the "strong guarantee" via money_get description
in 22.2.6.1.2/1:
"If a valid sequence is recognized, does not change err ; otherwise,
[..],
and does not change units or digits.[..]"
Until recently, the overall tendency seemed to be that less "complex"
types (no pun intended) obey the "strong guarantee", while larger
one's
only provide the "basic guarantee". This tendency has changed for
newer
types (random number engines and distributions).
bitset is a bit of a corner case: Personally I view at it as a
replacement
to bitmask types and thus should provide the current "strong
guarantee".
Besides recent changes to more safety we see that even for same
underlying types the behaviour is different, e.g. compare
basic_string
with a money unit stored as basic_string....
Greetings from Bremen,
Daniel
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: Gennaro Prota <gennaro.prota@yahoo.com>
Date: Mon, 2 Apr 2007 00:57:45 CST Raw View
On Sat, 31 Mar 2007 17:07:37 CST, Daniel Kr gler wrote:
>Gennaro Prota schrieb:
>
>> On Thu, 29 Mar 2007 14:52:38 GMT, Alberto Ganesh Barbati wrote:
>> >(notice that the number of binary digits produced is equal to the number
>> >of bits specified in the template argument).
>> >
>> >The issue about performances is that operator<< is implemented by first
>> >converting the number to a string and then outputting the string, thus
>> >potentially incurring in a dynamic allocation.
>>
>> Better late than never.. I think I'll make another attempt at getting
>> a reply for this:
>>
>> <http://google.com/group/comp.std.c++/msg/c2e71528fa98fa06>
>
>I would like to divide this discussion into two seperate concerns:
>
>1) Whether std::bitset could be implemented as described in
>your much earlier posting in the sense of as-if.
Thanks for the reawakening :-) One clarification: my original post
question was intended as "shall we necessarily use a string?", not
exactly as "is this specific implementation conforming?" (of course,
too, the "implementation" was just a rough sketch; were it in a formal
defect report I'd have paid more attention to it).
Basically, I think that if a string is required then the extractor is
over-specified.
You make a good point about transactional semantics. But, as you say
too, one could use a built-in array, or another bitset object, and
(what I meant to be) the main question --"is it ok to avoid using a
string?"-- would remain. IIRC, at the time I wrote the post I was
working on the inserters and extractors of boost::dynamic_bitset; I've
always been bothered by the coupling of std::bitset with
std::basic_string and I'd have liked dynamic_bitset not to go through
the same route. Alas, that has been a lost battle; apparently I was
also completely impotent against this:
<http://groups.google.com/group/comp.std.c++/browse_frm/thread/188ddd204ebd67da/739035f50ae29ab8>
>2) General inconsistencies of the current standard concerning
>transactionality of IO extractors.
>
>ad 1) Modulo possible errors in the code (I haven't checked
>so far),
I didn't check either :-) I just found easier to "talk C++" than
explaining things in English.
>I don't think that the proposed and obviously more
>performant implementation can be used as written as an
>alternative which fulfills as-if rules.
My point wasn't performance, though. It was about avoiding coupling to
the unnecessary (and IMHO, totally unrelated, abstraction-wise) string
facility. I suspected that, given that basic_string was already
required by other bitset parts, the committee found it convenient to
express the extractor requirements in terms of it, though nobody meant
that basic_string had to be used necessarily. That's why I asked.
PS: let me add that I'm snipping your other points just because I
haven't time to analyze them in detail; certainly not because I don't
consider them worthwhile.
--
Gennaro Prota.
In search of passioned C++ developers? I'm available.
Breeze C++: https://sourceforge.net/projects/breeze/
(incomplete, preview state)
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Mon, 2 Apr 2007 16:23:56 CST Raw View
Gennaro Prota schrieb:
> Thanks for the reawakening :-)
When I wrote this reply I considered for a while to
replace "reawakening" by "resurrection", which would
better fit into the current time (although ~one week too
early), but thematically worse ;-)
> One clarification: my original post
> question was intended as "shall we necessarily use a string?", not
> exactly as "is this specific implementation conforming?"
Sorry, but from both your response and the contents of
the older reference I could not see this intend.
> Basically, I think that if a string is required then the extractor is
> over-specified.
I agree, although I cannot surely decide whether the current
wordings demand that. This would lead us to the definition
and conformance against as-if again.
> But, as you say too, one could use a built-in array, or another
> bitset object, and (what I meant to be) the main question --"is
> it ok to avoid using a string?"-- would remain.
>From my view-point a well-written replacement using e.g.
a C array of fixed length would be sufficient to provide this
guarantee. The tricky point might be the situation of too
little free store, where an bad_alloc is thrown. E.g. can we
interpret the note given in 1.9
"For instance, an actual implementation need not evaluate
part of an expression if it can deduce that its value is not
used and that no side effects affecting the observable behavior
of the program are produced."
that every expression involving new/delete (in which hidden
way ever) *must* necessarily have observable side-effects
and that this means that we cannot replace them by
alternative options?
Viewing from the point of a global memory provider (new/delete)
this assumption applies.
But the standard often provides unexpected rear exits, e.g.
in the section about temporaries:
"Even when the creation of the temporary object is avoided
(12.8), all the semantic restrictions must be respected as if
the temporary object had been created."
Maybe a really *good* language lawyer can conclude from
this that it is possible to write the currently specified IO
extraction of bitset without a basic_string?
Personally I would say - although not granted by the
standard - that most resource limitations shouldn't be
included in the as-if rules. Here an artifical example: The
standard often writes some as-if code, which no
programmer would probably write, e.g. from stage 2 of
22.2.2.1.2:
"if ( ct == use_facet<numpunct<charT> >(loc ).decimal_point() )
c = '.';
bool discard =
( ct == use_facet<numpunct<charT> >(loc ).thousands_sep()
&&
use_facet<numpunct<charT> >(loc ).grouping().length() != 0 );"
Consider a reference-counter-like facet system as described
in 22.1.1.1.2/2. Theoretically I can write a program, which
systematically calls use_facet<numpunct<charT> >(loc ),
lets say std::numeric_limits<size_t>::max() - 2 times. The
following invokation of the above code, as written, would
lead to a welldefined unsigned overflow and can probably
have some funny effects on the lifetime management of the
facets. Does this mean that I'm not allowed to shorten the
above code using only *one* call to use_facet<numpunct<
charT> >(loc ), because that would possibly change side-
effects? Surely not.
> IIRC, at the time I wrote the post I was
> working on the inserters and extractors of boost::dynamic_bitset; I've
> always been bothered by the coupling of std::bitset with
> std::basic_string and I'd have liked dynamic_bitset not to go through
> the same route. Alas, that has been a lost battle; apparently I was
> also completely impotent against this:
>
> <http://groups.google.com/group/comp.std.c++/browse_frm/thread/188ddd204ebd67da/739035f50ae29ab8>
It depends on the view point, whether a battle has lost
here or not. It's rather obvious that there exists several
nastinesses with current binding between bitset and
string. Although closed as NAD the following report
points out similar problems with std::string and bitset:
http://www2.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#116
And the pure fact, that
http://www2.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#396
does still exists, is a sign that bitset IO is still an
active area. But I have to agree with Martin Sebor,
speaking in your "battle thread" - this not meant as
an attack ;-) - that we have to life with most currently
existing "features" like to_string from bitset.
Best is: Don't use it, if you don't have to. It would be
nice, if a standard *alternative* would be provided, but
the committee will never *replace* it by such thingee.
IMO its not sufficient to argue with "unwanted coupling"
here, because - as James Kanze recently said - there
also exists pro-arguments for using std::string in the
interface of other standard library components.
One of the lessons I learned from this discussion is,
that the bitset-string-connection is maybe a good
example, where *too early* and *too much* was done
in the first try. It's not so easy, to decide, what to leave
and what to use. Similarily std::exception's will now
have *additional* const char* c'tors parallel to those
taking std::string, and filestream will now have
*additional* std::string c'tors parallel to const char*.
> My point wasn't performance, though.
But this is a reasonable argument, here, too,
especially if we consider that bitset is actually a
similarily lightweight replacement for enumerations
(sort-of).
> It was about avoiding coupling to
> the unnecessary (and IMHO, totally unrelated, abstraction-wise) string
> facility. I suspected that, given that basic_string was already
> required by other bitset parts, the committee found it convenient to
> express the extractor requirements in terms of it, though nobody meant
> that basic_string had to be used necessarily. That's why I asked.
I understand that now and I also agree that
that the already existing string-bitset connection
probably lead to the "natural" solution to define
the IO insertion and extraction in terms of a
bitset-string transformation, but I'm not yet
conveniced that the current words would not
allow an alternative non-string transformation.
Greetings from Bremen,
Daniel
---
[ 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.comeaucomputing.com/csc/faq.html ]
Author: "James Kanze" <james.kanze@gmail.com>
Date: Tue, 3 Apr 2007 11:08:58 CST Raw View
On Apr 2, 8:57 am, Gennaro Prota <gennaro.pr...@yahoo.com> wrote:
> On Sat, 31 Mar 2007 17:07:37 CST, Daniel Kr gler wrote:
> >Gennaro Prota schrieb:
[...]
> You make a good point about transactional semantics. But, as you say
> too, one could use a built-in array, or another bitset object, and
> (what I meant to be) the main question --"is it ok to avoid using a
> string?"-- would remain.
Usual rule: can a conforming program tell? For std::istream, I
don't think so. For std::basic_istream< MyType, MyTraits >,
it's less obvious, because the type of string which it should
use is std::basic_string< MyType, MyTraits > (so you can get
control in some way).
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "James Kanze" <james.kanze@gmail.com>
Date: Tue, 3 Apr 2007 11:27:24 CST Raw View
On Apr 3, 12:23 am, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> Gennaro Prota schrieb:
> > Basically, I think that if a string is required then the extractor is
> > over-specified.
> I agree, although I cannot surely decide whether the current
> wordings demand that. This would lead us to the definition
> and conformance against as-if again.
C++98 said that the implementation used "string"; I don't think
you can detect if it doesn't, so as-if covers it. The current
draft says that the implementation used basic_string< charT,
traits >, which means that it uses a traits class which I wrote;
that might provide a means.
Note that this change (between C++98 and the current draft)
could also conceivably break code. Again, however, it would
require a really perverse traits class, and I'll bet that in
practice, no real code is affected.
> > But, as you say too, one could use a built-in array, or another
> > bitset object, and (what I meant to be) the main question --"is
> > it ok to avoid using a string?"-- would remain.
> From my view-point a well-written replacement using e.g.
> a C array of fixed length would be sufficient to provide this
> guarantee. The tricky point might be the situation of too
> little free store,
You don't need any free store, since you can allocate on stack:
charT buffer[ N ] ;
> where an bad_alloc is thrown. E.g. can we
> interpret the note given in 1.9
> "For instance, an actual implementation need not evaluate
> part of an expression if it can deduce that its value is not
> used and that no side effects affecting the observable behavior
> of the program are produced."
> that every expression involving new/delete (in which hidden
> way ever) *must* necessarily have observable side-effects
> and that this means that we cannot replace them by
> alternative options?
That's the way I've always interpreted it. Particularly in that
the standard, in some cases, takes pains to decouple the two,
e.g. 20.6.1.1/6 "the storage is obtained by calling ::operator
new(std::size_t), but it is unspecified when or how often this
function is called." If an implementation had the right,
generally, to skip dynamic allocation, then this sentence
wouldn't be necessary.
> Viewing from the point of a global memory provider (new/delete)
> this assumption applies.
> But the standard often provides unexpected rear exits, e.g.
> in the section about temporaries:
> "Even when the creation of the temporary object is avoided
> (12.8), all the semantic restrictions must be respected as if
> the temporary object had been created."
> Maybe a really *good* language lawyer can conclude from
> this that it is possible to write the currently specified IO
> extraction of bitset without a basic_string?
For the moment, I'd like to see a conforming program which could
tell.
> Personally I would say - although not granted by the
> standard - that most resource limitations shouldn't be
> included in the as-if rules.
Exceeding resource limitations is undefined behavior. (I forget
where it says this in the standard, but someone showed it to me
once.) In some ways, it's unavoidable: you're allowed to
declare an array of 1 Mo on the stack, and you're allowed to
recurse, but it's a good bet that if you do both in the same
function, something's going to give very, very quickly.
> Here an artifical example: The
> standard often writes some as-if code, which no
> programmer would probably write, e.g. from stage 2 of
> 22.2.2.1.2:
> "if ( ct == use_facet<numpunct<charT> >(loc ).decimal_point() )
> c = '.';
> bool discard =
> ( ct == use_facet<numpunct<charT> >(loc ).thousands_sep()
> &&
> use_facet<numpunct<charT> >(loc ).grouping().length() != 0 );"
> Consider a reference-counter-like facet system as described
> in 22.1.1.1.2/2. Theoretically I can write a program, which
> systematically calls use_facet<numpunct<charT> >(loc ),
> lets say std::numeric_limits<size_t>::max() - 2 times. The
> following invokation of the above code, as written, would
> lead to a welldefined unsigned overflow and can probably
> have some funny effects on the lifetime management of the
> facets. Does this mean that I'm not allowed to shorten the
> above code using only *one* call to use_facet<numpunct<
> charT> >(loc ), because that would possibly change side-
> effects? Surely not.
I'm not sure about your example. Calling use_facet has no
effect on any reference count. The reference count refers to
the number of locale objects which contain the facet, and I'm
willing to bet that with most implementations, you'll run out of
memory long before you overflow. On the other hand, there's
also no requirement with regards to how and where the
implementation performs its reference counting. The fact that
the "flag" you pass to the constructor is in fact a size_t which
can take only two numeric values, rather than a bool, is very
suggestive, but presumably, an implementation could maintain the
reference counts on a simple signed char, and beg out on
"resources exceeded" when it overflowed.
> > IIRC, at the time I wrote the post I was
> > working on the inserters and extractors of boost::dynamic_bitset; I've
> > always been bothered by the coupling of std::bitset with
> > std::basic_string and I'd have liked dynamic_bitset not to go through
> > the same route. Alas, that has been a lost battle; apparently I was
> > also completely impotent against this:
> > <http://groups.google.com/group/comp.std.c++/browse_frm/thread/188ddd2...>
> It depends on the view point, whether a battle has lost
> here or not. It's rather obvious that there exists several
> nastinesses with current binding between bitset and
> string. Although closed as NAD
Note that NAD doesn't mean that the committee thinks everything
is perfect. It means that any changes required would go beyond
the scope of "fixing a defect". In the sense used here, a
"defect" is an internal contradiction or inconsistency in the
standard itself, something which isn't clear, or (possibly) a
failure to express the actual intent of what was adopted by vote
in the committee.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]