Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > ptr_fun & tolower confusion

Reply
Thread Tools

ptr_fun & tolower confusion

 
 
Greg Herlihy
Guest
Posts: n/a
 
      07-04-2008
On Jul 4, 2:34 am, Kai-Uwe Bux <(E-Mail Removed)> wrote:
> Soumen wrote:
> > I wanted convert a mixed case string to a lower case one. And I tried
> > following code:

>
> > std::transform(mixedCaseString.begin(), mixedCaseString::end(),
> > mixedCaseString.begin(), std:tr_fun(tolower));

>
> Slightly modified from the archive:
>
> #include <tr1/memory>
> #include <cstdlib>
> #include <locale>
>
> template < typename CharT >
> class to_lower {
>
> typedef std::ctype< CharT > char_type;
>
> std::tr1::shared_ptr< std::locale > the_loc_ptr;
> char_type const * the_type_ptr;
>
> public:
>
> to_lower ( std::locale const & r_loc = std::locale() )
> : the_loc_ptr ( new std::locale ( r_loc ) )
> , the_type_ptr ( &std::use_facet< char_type >( *the_loc_ptr ) )
> {}
>
> CharT operator() ( CharT chr ) const {
> return ( the_type_ptr->tolower( chr ) );
> }
>
> };


TR1's shared_ptr<> class is not nearly as useful in this case as its
bind() routine. In fact, calling TR1's bind() would eliminate the
custom to_lower functor and its attendant complexity.

After all, lowercasing a C++ string seems like it should be a fairly
straightforward task - one that should require only a few lines of
code::

#include <iostream>
#include <string>
#include <algorithm>
#include <locale>

#include <tr1/functional>

using std::locale;
using std::tolower;
using std::tr1::bind;
using std::tr1:laceholders::_1;

int main()
{
std::string s("GrEg");

transform( s.begin(), s.end(), s.begin(),
bind( tolower<char>, _1, locale()));

std::cout << s << "\n";
}

Program Output:

greg


 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      07-05-2008
On Jul 4, 10:31 pm, Kai-Uwe Bux <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > On Jul 4, 11:34 am, Kai-Uwe Bux <(E-Mail Removed)> wrote:
> >> Soumen wrote:


> > Just curious, but...


> >> Slightly modified from the archive:

>
> >> #include <tr1/memory>
> >> #include <cstdlib>
> >> #include <locale>


> >> template < typename CharT >
> >> class to_lower {


> >> typedef std::ctype< CharT > char_type;

>
> >> std::tr1::shared_ptr< std::locale > the_loc_ptr;
> >> char_type const * the_type_ptr;


> >> public:


> >> to_lower ( std::locale const & r_loc = std::locale() )
> >> : the_loc_ptr ( new std::locale ( r_loc ) )


> > Why the new, and the smart pointer? I just use a locale member.
> > (If it's part of an actual application, I'll often forego
> > keeping a copy of the locale anyway---most of the applications I
> > work on don't play around with locales, so I'm generally sure
> > that the locale I'm using won't go away.)


> No particular reason other than history of the code.


OK. The usual reason in real code, in sum.

> It started out as an internal class and was only used in
> placed where life-time of temporaries guaranteed that the
> locale object would not go away. That class had a locale
> pointer (or maybe a reference). So when the code was moved
> into a different context where life-time guarantees became
> problematic, the pointer got replaced by a smart pointer just
> to solve the life-time issue. I guess it's mainly
> psychological: it was a pointer, it became a smart pointer.
> That's all.


> Probably, a locale member is better. One would not expect
> algorithms to copy functors ruthlessly.


Interesting. My version had a similar history, except that in
the early versions, I didn't keep a pointer to the locale at
all; all I needed, after all, was the ctype. So when lifetime
of the locale (which controls the lifetime of the facet, for
those who might not be following us) became an issue, I created
a copy of the locale in the most convenient place; from what I
gather from the standard (although it probably shouldn't be used
as a design document), locales were designed to be copied, at a
more or less reasonable cost.

And, of course, I'm a very strong believer in the idea that if
you don't need arbitrary and explicit lifetime, you shouldn't be
using new.

But I don't think it makes a real difference.

--
James Kanze (GABI Software) email:(E-Mail Removed)
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
 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      07-05-2008
On Jul 4, 10:52 pm, Greg Herlihy <(E-Mail Removed)> wrote:
> On Jul 4, 2:34 am, Kai-Uwe Bux <(E-Mail Removed)> wrote:


[...]
> > Slightly modified from the archive:


> > #include <tr1/memory>
> > #include <cstdlib>
> > #include <locale>


> > template < typename CharT >
> > class to_lower {


> > typedef std::ctype< CharT > char_type;


> > std::tr1::shared_ptr< std::locale > the_loc_ptr;
> > char_type const * the_type_ptr;


> > public:


> > to_lower ( std::locale const & r_loc = std::locale() )
> > : the_loc_ptr ( new std::locale ( r_loc ) )
> > , the_type_ptr ( &std::use_facet< char_type >( *the_loc_ptr ) )
> > {}


> > CharT operator() ( CharT chr ) const {
> > return ( the_type_ptr->tolower( chr ) );
> > }


> > };


> TR1's shared_ptr<> class is not nearly as useful in this case
> as its bind() routine. In fact, calling TR1's bind() would
> eliminate the custom to_lower functor and its attendant
> complexity.


> After all, lowercasing a C++ string seems like it should be a
> fairly straightforward task - one that should require only a
> few lines of code::


> #include <iostream>
> #include <string>
> #include <algorithm>
> #include <locale>


> #include <tr1/functional>


> using std::locale;
> using std::tolower;
> using std::tr1::bind;
> using std::tr1:laceholders::_1;


> int main()
> {
> std::string s("GrEg");


> transform( s.begin(), s.end(), s.begin(),
> bind( tolower<char>, _1, locale()));
> std::cout << s << "\n";
> }


That is, of course, the simplest solution. It hasn't been
available all that long, however, and most of us developed our
solution before bind was available. (The shared_ptr isn't
really necessary here, and even if it was, most of us had simple
implementations of shared_ptr long before it made it into TR1.)

And IMHO, there's nothing wrong with providing a general wrapped
tool (although it does lead to the mistaken belief that you can
generally use tranform for converting to lower case---in
practice, the mapping isn't one to one). And using the ctype
directly will probably be slightly faster (although I doubt that
that is an issue).

--
James Kanze (GABI Software) email:(E-Mail Removed)
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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problem with library design: support both std::ptr_fun and functor Fei Liu C++ 5 08-21-2007 02:03 PM
Compiles with tolower from global namespace but not with std::tolower Eric Lilja C++ 4 09-02-2005 09:42 PM
Why do we need seperate ptr_fun/mem_fun/mem_fun_ref functions? ShaneG C++ 4 05-24-2005 10:29 AM
tolower conflict with iostream? David Rubin C++ 13 10-14-2003 08:58 AM
tolower used by transform qazmlp C++ 3 07-23-2003 03:16 PM



Advertisments