This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
RE: Q about ctype.narrow
- From: Pétur Runólfsson <peturr02 at ru dot is>
- To: "Jerry Quinn" <jlquinn at optonline dot net>
- Cc: "Paolo Carlini" <pcarlini at unitus dot it>,"libstdc++" <libstdc++ at gcc dot gnu dot org>
- Date: Wed, 26 Nov 2003 09:08:56 -0000
- Subject: RE: Q about ctype.narrow
Jerry Quinn wrote:
> Pétur Runólfsson writes:
> > Jerry Quinn wrote:
> > > Here's the issue. Assume we have ctype<char> that has been
> subclassed
> > > by a library client. Now:
> > >
> > > char ctype<char>::narrow(char c, char default)
> > > {
> > > if (table[c]) return table[c];
> > > return table[c] = do_narrow(c, default);
> > > }
> >
> > I don't think this is allowed under the as-if rule. (Calling a virtual
> > function is an observable effect.)
>
> I hope that's not required by the standard. If so, it clobbers ANY
> optimization that caches values from virtual function calls. You
> wouldn't be able to to cache widen results for numpunct fields, for
> example, since the spec says that the results have to be as if all the
> various do_widen's happened on a particular call.
No. There is a special exception in 22.1.1 p7 (modified by DR 360)
that allows users of locale to cache return values. Note that it
says "facet object installed in the same locale" so in:
ostream os(...);
os.widen('\n'); // Must call ctype::do_widen(char).
os.widen('\n'); // May use cached value.
os.imbue(os.getloc().combine<numpunct<char> >(locale("")));
// Same ctype facet, but different locale => must call
// ctype::do_widen again.
os.widen('\n');
The numpunct_cache meets this requirement, so it's OK. Also, since
only facets that are installed in locales are bound by this rule,
this would be OK, so long as this facet is never put in a locale:
class Qux : public ctype<char>
{
protected:
char do_widen(char c) const { return (c + time(NULL)) % 256; }
};
There is also a problem if virtual members of facets are called
during construction. Consider this testcase:
class Foo : public ctype<char>
{
public:
Foo() { widen('\n'); } // Calls Foo::do_widen('\n');
};
class Bar : public Foo
{
protected:
char do_widen(char c) const { return ~c; }
};
Bar bar;
// Should return ~'\n', will return '\n' if the cache is in widen.
char c = bar.widen('\n');
These testcases are all somewhat silly, but IMHO so is any testcase
that overrides ctype<char>::do_widen or do_narrow. The best
optimization might actually be something like this:
const ctype<char>& ct = ...;
// Should be cached so that typeid is only called once:
bool trivial = (typeid(ct) == typeid(ctype<char>));
if (trivial)
// Don't call narrow or widen
else
// Call narrow and widen
Regards,
Petur