Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Unary functor on algorithm using copy constructor

Reply
Thread Tools

Unary functor on algorithm using copy constructor

 
 
Dijkstra
Guest
Posts: n/a
 
      07-08-2008
Hi folks!

First, this is the code I'm using to expose the problem:

------------------------------------------------------------------
#include <functional>
#include <string>
#include <iostream>

using namespace std;

struct space_comparer : public unary_function<char, bool> {

mutable argument_type __lastChar;

space_comparer()
{
__lastChar = 'X';
cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
endl;
}

space_comparer(const space_comparer &__src)
{
cout << "copy ctor() called setting lastChar to 'Y'" << endl;
__lastChar = 'Y';
}

result_type operator ()(const argument_type c) const
{
cout << "[" << __lastChar << " | " << c << "]" << endl;
__lastChar = c;
return ::isspace(c);
}

};


main()
{
string cad1;
string cad2;

const space_comparer instance;

cad1 = "cpp";

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );
remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );
remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );

return 0;
}
---------------------------------------------------------------

OK, so the meaning of all that is to use a unary function with a
persistent "state", so that the "space_comparer" works by using
previous values. My problem is that the "remove_copy_if" algorithm,
and I think all algorithms, use a copy.

I mean, suppose this call:

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
space_comparer() );

This works by constructing a new "space_comparer" functor object and
using its instance for all the algorithm lifetime. What I like to do
is use an actual instance as the predicate, so that it can mantain a
state across algorithm calls.

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );

I supposed the above call would reuse the "instance" of the object
functor, which indeed does. But it does a temporary copy of the object
and it works with it, leaving the original instance untouched. The
output of the above code is:

-----------------------------------------------------------------
ctor() called and lastChar is 'X'
copy ctor() called setting lastChar to 'Y'
[Y | c]
[c | p]
[p | p]
copy ctor() called setting lastChar to 'Y'
[Y | c]
[c | p]
[p | p]
copy ctor() called setting lastChar to 'Y'
[Y | c]
[c | p]
[p | p]
-----------------------------------------------------------------

But, the expected output needs to be like this:

-----------------------------------------------------------------
ctor() called and lastChar is 'X'
[X | c]
[c | p]
[p | p]
[p | c] <<--- Note previous state of "lastChar"
[c | p]
[p | p]
[p | c] <<--- Note previous state of "lastChar"
[c | p]
[p | p]
-----------------------------------------------------------------

I don't know if this is at all possible. I already tried with
"mem_func" and such techniques, but to no avail...

Please, I'm not so STL literate, so bear with me.

Cheers,
 
Reply With Quote
 
 
 
 
Jim Langston
Guest
Posts: n/a
 
      07-08-2008

"Dijkstra" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Hi folks!
>
> First, this is the code I'm using to expose the problem:
>
> ------------------------------------------------------------------
> #include <functional>
> #include <string>
> #include <iostream>
>
> using namespace std;
>
> struct space_comparer : public unary_function<char, bool> {
>
> mutable argument_type __lastChar;


If you need one, and only one __lastChar (a bad choice of names, by the way)
then you should make it static. I don't think that mutable makes it static.

static argument_type lastChar_;

Underscores in the front of variable names are generally reerved for the
compiler,t here are different rules as to which are and which aren't, it is
best to just never use preceeding underscore for you own variables.

> space_comparer()
> {
> __lastChar = 'X';
> cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
> endl;
> }
>
> space_comparer(const space_comparer &__src)
> {
> cout << "copy ctor() called setting lastChar to 'Y'" << endl;
> __lastChar = 'Y';
> }
>
> result_type operator ()(const argument_type c) const
> {
> cout << "[" << __lastChar << " | " << c << "]" << endl;
> __lastChar = c;
> return ::isspace(c);
> }
>
> };
>
>
> main()
> {
> string cad1;
> string cad2;
>
> const space_comparer instance;
>
> cad1 = "cpp";
>
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
>
> return 0;
> }
> ---------------------------------------------------------------
>
> OK, so the meaning of all that is to use a unary function with a
> persistent "state", so that the "space_comparer" works by using
> previous values. My problem is that the "remove_copy_if" algorithm,
> and I think all algorithms, use a copy.
>
> I mean, suppose this call:
>
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> space_comparer() );
>
> This works by constructing a new "space_comparer" functor object and
> using its instance for all the algorithm lifetime. What I like to do
> is use an actual instance as the predicate, so that it can mantain a
> state across algorithm calls.
>
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
>
> I supposed the above call would reuse the "instance" of the object
> functor, which indeed does. But it does a temporary copy of the object
> and it works with it, leaving the original instance untouched. The
> output of the above code is:
>
> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> -----------------------------------------------------------------
>
> But, the expected output needs to be like this:
>
> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> [X | c]
> [c | p]
> [p | p]
> [p | c] <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> [p | c] <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> -----------------------------------------------------------------
>
> I don't know if this is at all possible. I already tried with
> "mem_func" and such techniques, but to no avail...
>
> Please, I'm not so STL literate, so bear with me.
>
> Cheers,



 
Reply With Quote
 
 
 
 
red floyd
Guest
Posts: n/a
 
      07-09-2008
Jim Langston wrote:
> "Dijkstra" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Hi folks!
>>
>> First, this is the code I'm using to expose the problem:
>>
>> ------------------------------------------------------------------
>> #include <functional>
>> #include <string>
>> #include <iostream>
>>
>> using namespace std;
>>
>> struct space_comparer : public unary_function<char, bool> {
>>
>> mutable argument_type __lastChar;

>
> If you need one, and only one __lastChar (a bad choice of names, by the way)
> then you should make it static. I don't think that mutable makes it static.
>

In this particular case, the code is bad. Per ISO/IEC 14882:2003, all
identifiers containing a double underscore are reserved to the
implementation (when the standard library is used -- and it is).
 
Reply With Quote
 
Vishesh
Guest
Posts: n/a
 
      07-09-2008
On Jul 8, 10:14*pm, "Jim Langston" <(E-Mail Removed)> wrote:
> "Dijkstra" <(E-Mail Removed)> wrote in message
>
> news:(E-Mail Removed)...
>
> > Hi folks!

>
> > First, this is the code I'm using to expose the problem:

>
> > ------------------------------------------------------------------
> > #include <functional>
> > #include <string>
> > #include <iostream>

>
> > using namespace std;

>
> > struct space_comparer : public unary_function<char, bool> {

>
> > mutable argument_type *__lastChar;

>
> If you need one, and only one __lastChar (a bad choice of names, by the way)
> then you should make it static. *I don't think that mutable makes it static.
>
> static argument_type lastChar_;
>
> Underscores in the front of variable names are generally reerved for the
> compiler,t here are different rules as to which are and which aren't, it is
> best to just never use preceeding underscore for you own variables.
>
> > space_comparer()
> > {
> > __lastChar = 'X';
> > cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
> > endl;
> > }

>
> > space_comparer(const space_comparer &__src)
> > {
> > cout << "copy ctor() called setting lastChar to 'Y'" << endl;
> > __lastChar = 'Y';
> > }

>
> > result_type operator ()(const argument_type c) const
> > {
> > cout << "[" << __lastChar << " | " << c << "]" << endl;
> > __lastChar = c;
> > return ::isspace(c);
> > }

>
> > };

>
> > main()
> > {
> > string cad1;
> > string cad2;

>
> > const space_comparer instance;

>
> > cad1 = "cpp";

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );

>
> > return 0;
> > }
> > ---------------------------------------------------------------

>
> > OK, so the meaning of all that is to use a unary function with a
> > persistent "state", so that the "space_comparer" works by using
> > previous values. My problem is that the "remove_copy_if" algorithm,
> > and I think all algorithms, use a copy.

>
> > I mean, suppose this call:

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > space_comparer() );

>
> > This works by constructing a new "space_comparer" functor object and
> > using its instance for all the algorithm lifetime. What I like to do
> > is use an actual instance as the predicate, so that it can mantain a
> > state across algorithm calls.

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );

>
> > I supposed the above call would reuse the "instance" of the object
> > functor, which indeed does. But it does a temporary copy of the object
> > and it works with it, leaving the original instance untouched. The
> > output of the above code is:

>
> > -----------------------------------------------------------------
> > ctor() called and lastChar is 'X'
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > -----------------------------------------------------------------

>
> > But, the expected output needs to be like this:

>
> > -----------------------------------------------------------------
> > ctor() called and lastChar is 'X'
> > [X | c]
> > [c | p]
> > [p | p]
> > [p | c] * <<--- Note previous state of "lastChar"
> > [c | p]
> > [p | p]
> > [p | c] * <<--- Note previous state of "lastChar"
> > [c | p]
> > [p | p]
> > -----------------------------------------------------------------

>
> > I don't know if this is at all possible. I already tried with
> > "mem_func" and such techniques, but to no avail...

>
> > Please, I'm not so STL literate, so bear with me.

>
> > Cheers,

>
>


As far as I know. The keyword "mutuable" implies that you may change
the value of the variable even though the class/struct is a const.

Eg -
const space_comparer s;
s.__lastChar = 'V'; //totally valid

Now getting to the point. As already stated by Jim you can use a
static member to get the expected results. Predicates are usually not
passed by reference. Thats why the copy constructor is called each
time.
 
Reply With Quote
 
Vishesh
Guest
Posts: n/a
 
      07-09-2008
On Jul 8, 9:50*pm, Dijkstra <(E-Mail Removed)> wrote:
> Hi folks!
>
> First, this is the code I'm using to expose the problem:
>
> ------------------------------------------------------------------
> #include <functional>
> #include <string>
> #include <iostream>
>
> using namespace std;
>
> struct space_comparer : public unary_function<char, bool> {
>
> * * * * mutable argument_type *__lastChar;
>
> * * * * space_comparer()
> * * * * {
> * * * * * * * * __lastChar = 'X';
> * * * * * * * * cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
> endl;
> * * * * }
>
> * * * * space_comparer(const space_comparer &__src)
> * * * * {
> * * * * * * * * cout << "copy ctor() called setting lastChar to 'Y'" << endl;
> * * * * * * * * __lastChar = 'Y';
> * * * * }
>
> * * * * result_type operator ()(const argument_type c) const
> * * * * {
> * * * * * * * * cout << "[" << __lastChar << " | " << c << "]" << endl;
> * * * * * * * * __lastChar = c;
> * * * * * * * * return ::isspace(c);
> * * * * }
>
> };
>
> main()
> {
> * * * * string cad1;
> * * * * string cad2;
>
> * * * * const space_comparer instance;
>
> * * * * cad1 = "cpp";
>
> * * * * remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> * * * * remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> * * * * remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
>
> * * * * return 0;}
>
> ---------------------------------------------------------------
>
> OK, so the meaning of all that is to use a unary function with a
> persistent "state", so that the "space_comparer" works by using
> previous values. My problem is that the "remove_copy_if" algorithm,
> and I think all algorithms, use a copy.
>
> I mean, suppose this call:
>
> * * * * remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> space_comparer() );
>
> This works by constructing a new "space_comparer" functor object and
> using its instance for all the algorithm lifetime. What I like to do
> is use an actual instance as the predicate, so that it can mantain a
> state across algorithm calls.
>
> * * * * remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
>
> I supposed the above call would reuse the "instance" of the object
> functor, which indeed does. But it does a temporary copy of the object
> and it works with it, leaving the original instance untouched. The
> output of the above code is:
>
> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> -----------------------------------------------------------------
>
> But, the expected output needs to be like this:
>
> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> [X | c]
> [c | p]
> [p | p]
> [p | c] * <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> [p | c] * <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> -----------------------------------------------------------------
>
> I don't know if this is at all possible. I already tried with
> "mem_func" and such techniques, but to no avail...
>
> Please, I'm not so STL literate, so bear with me.
>
> Cheers,


On Jul 8, 10:14 pm, "Jim Langston" <(E-Mail Removed)> wrote:
> "Dijkstra" <(E-Mail Removed)> wrote in message
>
> news:(E-Mail Removed)...
>
> > Hi folks!

>
> > First, this is the code I'm using to expose the problem:

>
> > ------------------------------------------------------------------
> > #include <functional>
> > #include <string>
> > #include <iostream>

>
> > using namespace std;

>
> > struct space_comparer : public unary_function<char, bool> {

>
> > mutable argument_type __lastChar;

>
> If you need one, and only one __lastChar (a bad choice of names, by the way)
> then you should make it static. I don't think that mutable makes it static.
>
> static argument_type lastChar_;
>
> Underscores in the front of variable names are generally reerved for the
> compiler,t here are different rules as to which are and which aren't, it is
> best to just never use preceeding underscore for you own variables.
>
> > space_comparer()
> > {
> > __lastChar = 'X';
> > cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
> > endl;
> > }

>
> > space_comparer(const space_comparer &__src)
> > {
> > cout << "copy ctor() called setting lastChar to 'Y'" << endl;
> > __lastChar = 'Y';
> > }

>
> > result_type operator ()(const argument_type c) const
> > {
> > cout << "[" << __lastChar << " | " << c << "]" << endl;
> > __lastChar = c;
> > return ::isspace(c);
> > }

>
> > };

>
> > main()
> > {
> > string cad1;
> > string cad2;

>
> > const space_comparer instance;

>
> > cad1 = "cpp";

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );

>
> > return 0;
> > }
> > ---------------------------------------------------------------

>
> > OK, so the meaning of all that is to use a unary function with a
> > persistent "state", so that the "space_comparer" works by using
> > previous values. My problem is that the "remove_copy_if" algorithm,
> > and I think all algorithms, use a copy.

>
> > I mean, suppose this call:

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > space_comparer() );

>
> > This works by constructing a new "space_comparer" functor object and
> > using its instance for all the algorithm lifetime. What I like to do
> > is use an actual instance as the predicate, so that it can mantain a
> > state across algorithm calls.

>
> > remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> > instance );

>
> > I supposed the above call would reuse the "instance" of the object
> > functor, which indeed does. But it does a temporary copy of the object
> > and it works with it, leaving the original instance untouched. The
> > output of the above code is:

>
> > -----------------------------------------------------------------
> > ctor() called and lastChar is 'X'
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > copy ctor() called setting lastChar to 'Y'
> > [Y | c]
> > [c | p]
> > [p | p]
> > -----------------------------------------------------------------

>
> > But, the expected output needs to be like this:

>
> > -----------------------------------------------------------------
> > ctor() called and lastChar is 'X'
> > [X | c]
> > [c | p]
> > [p | p]
> > [p | c] <<--- Note previous state of "lastChar"
> > [c | p]
> > [p | p]
> > [p | c] <<--- Note previous state of "lastChar"
> > [c | p]
> > [p | p]
> > -----------------------------------------------------------------

>
> > I don't know if this is at all possible. I already tried with
> > "mem_func" and such techniques, but to no avail...

>
> > Please, I'm not so STL literate, so bear with me.

>
> > Cheers,

>
>


As far as I know. The keyword "mutuable" implies that you may change
the value of the variable even though the class/struct is a const.

Eg -
const space_comparer s;
s.__lastChar = 'V'; //totally valid

Now getting to the point. As already stated by Jim you can use a
static member to get the expected results. Predicates are usually not
passed by reference. Thats why the copy constructor is called each
time.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-09-2008
On Jul 8, 6:50 pm, Dijkstra <(E-Mail Removed)> wrote:
> First, this is the code I'm using to expose the problem:


> ------------------------------------------------------------------
> #include <functional>
> #include <string>
> #include <iostream>


> using namespace std;


> struct space_comparer : public unary_function<char, bool> {
>
> mutable argument_type __lastChar;
>
> space_comparer()
> {
> __lastChar = 'X';
> cout << "ctor() called and lastChar is '" << __lastChar << "'" <<
> endl;
> }


> space_comparer(const space_comparer &__src)
> {
> cout << "copy ctor() called setting lastChar to 'Y'" << endl;
> __lastChar = 'Y';
> }


> result_type operator ()(const argument_type c) const
> {
> cout << "[" << __lastChar << " | " << c << "]" << endl;
> __lastChar = c;
> return ::isspace(c);
> }
> };


> main()
> {
> string cad1;
> string cad2;


> const space_comparer instance;


> cad1 = "cpp";


> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );
> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );


> return 0;}


> ---------------------------------------------------------------


> OK, so the meaning of all that is to use a unary function with
> a persistent "state", so that the "space_comparer" works by
> using previous values. My problem is that the "remove_copy_if"
> algorithm, and I think all algorithms, use a copy.


The predicate object is passed by copy, so all they have is a
copy to begin with; they have no means of accessing the orginal
object.

> I mean, suppose this call:


> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> space_comparer() );


> This works by constructing a new "space_comparer" functor
> object and using its instance for all the algorithm lifetime.
> What I like to do is use an actual instance as the predicate,
> so that it can mantain a state across algorithm calls.


The problem is that in order to do that, the algorithm would
have to declare the predicate parameter as a reference. A const
reference, if the above is to work.

> remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
> instance );


> I supposed the above call would reuse the "instance" of the
> object functor, which indeed does. But it does a temporary
> copy of the object and it works with it, leaving the original
> instance untouched. The output of the above code is:


> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> copy ctor() called setting lastChar to 'Y'
> [Y | c]
> [c | p]
> [p | p]
> -----------------------------------------------------------------


Which is what is required by the standard.

> But, the expected output needs to be like this:


> -----------------------------------------------------------------
> ctor() called and lastChar is 'X'
> [X | c]
> [c | p]
> [p | p]
> [p | c] <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> [p | c] <<--- Note previous state of "lastChar"
> [c | p]
> [p | p]
> -----------------------------------------------------------------


> I don't know if this is at all possible. I already tried with
> "mem_func" and such techniques, but to no avail...


> Please, I'm not so STL literate, so bear with me.


A long time ago, there was a saying: "The solution to every
problem is an additional level of indirection." Change your
space_comparer to contain a char* as member, provide a
constructor which takes an char* as argument, and use that,
declaring the char before the predicate.

--
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
 
Dijkstra
Guest
Posts: n/a
 
      07-09-2008
Hi Jim!

On Jul 8, 7:14*pm, "Jim Langston" <(E-Mail Removed)> wrote:

> > struct space_comparer : public unary_function<char, bool> {

>
> > mutable argument_type *__lastChar;

>
> If you need one, and only one __lastChar (a bad choice of names, by the way)
> then you should make it static. *I don't think that mutable makes it static.
>
> static argument_type lastChar_;


I knew many of you would be instantly caught by the double_underscore
issue. I know, I know, it's a bad habit and I promise to flagelate
myself later on.

About the static member attribute, I can't do that since the very use
of static members would kill the multithreaded nature of the program.
The code which used the functor will be automatically non-reentrant,
adding serialization here is killer.

"mutable" attributes can be modified inside "const" functions, i.e.
they don't add to the "const-ness" of the class. Absolutely they don't
become static.

Actually, I come to a solution which I think it's the best suited for
my implementation. It involves using a reference, which is used
instead of the actual member. However, I'm curious about the correct
(and formal) solution, so folks, keep replying...

Thanks for your answers,
Dijkstra.
 
Reply With Quote
 
Dijkstra
Guest
Posts: n/a
 
      07-09-2008
Hi red!

On Jul 9, 5:48*am, red floyd <(E-Mail Removed)> wrote:

> In this particular case, the code is bad. *Per ISO/IEC 14882:2003, all
> identifiers containing a double underscore are reserved to the
> implementation (when the standard library is used -- and it is).


Don't worry red, actually I'm doing this rule in the Makefile:

cat @< | sed s/__/m_/g > ISO_enabled_code_@<
$(CXX) $(CXXFLAGS) -o $@ -c ISO_enabled_code_$<

So as to compile in ISO/IEC enabled mode.

Cheers,
Dijkstra.
 
Reply With Quote
 
Jim Langston
Guest
Posts: n/a
 
      07-09-2008

"Dijkstra" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
Hi Jim!

On Jul 8, 7:14 pm, "Jim Langston" <(E-Mail Removed)> wrote:

> > struct space_comparer : public unary_function<char, bool> {

>
> > mutable argument_type __lastChar;

>
> If you need one, and only one __lastChar (a bad choice of names, by the
> way)
> then you should make it static. I don't think that mutable makes it
> static.
>
> static argument_type lastChar_;


I knew many of you would be instantly caught by the double_underscore
issue. I know, I know, it's a bad habit and I promise to flagelate
myself later on.

About the static member attribute, I can't do that since the very use
of static members would kill the multithreaded nature of the program.
The code which used the functor will be automatically non-reentrant,
adding serialization here is killer.

"mutable" attributes can be modified inside "const" functions, i.e.
they don't add to the "const-ness" of the class. Absolutely they don't
become static.

Actually, I come to a solution which I think it's the best suited for
my implementation. It involves using a reference, which is used
instead of the actual member. However, I'm curious about the correct
(and formal) solution, so folks, keep replying...

----------------------

This is what I came up with playing around. If you use some sort of smart
pointer you may get around having to do the CleanUp. I don't know if thsi
is "right" but seems to be doable. Output is:

ctor() called and lastChar is 'X'
copy ctor() called setting lastCharP
copy ctor() called setting lastCharP
[X | c]
[c | p]
[p | p]
copy ctor() called setting lastCharP
copy ctor() called setting lastCharP
[p | c]
[c | p]
[p | p]
copy ctor() called setting lastCharP
copy ctor() called setting lastCharP
[p | c]
[c | p]
[p | p]

#include <functional>
#include <string>
#include <iostream>
#include <algorithm>

struct space_comparer : public std::unary_function<char, bool> {

mutable argument_type* lastCharP;

space_comparer()
{
lastCharP = new argument_type;
*lastCharP = 'X';
std::cout << "ctor() called and lastChar is '" << *lastCharP << "'"
<< std::endl;
}

void CleanUp() const
{
delete lastCharP;
lastCharP = NULL;
}

space_comparer(const space_comparer &__src)
{
std::cout << "copy ctor() called setting lastCharP" << std::endl;
lastCharP = __src.lastCharP;
}

result_type operator ()(const argument_type c) const
{
std::cout << "[" << *lastCharP << " | " << c << "]" << std::endl;
*lastCharP = c;
return ::isspace(c);
}

};

int main()
{
std::string cad1;
std::string cad2;

const space_comparer instance;

cad1 = "cpp";

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );
remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );
remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad2),
instance );

instance.CleanUp();

return 0;
}


 
Reply With Quote
 
Dijkstra
Guest
Posts: n/a
 
      07-09-2008
Hi All!

I would like to thanks Jim Langston, James Kanze, Vishesh and all of
you who replied with interesting and usefull stuff.

The predicates in the functors are indeed passed by value (copies).
This is required by the standard template library to properly do it's
magic. I don't deeply understand the formality of all this, but in
practice I suspect it has something to do with the fact you can't
double reference something (i.e: &&something --> You can't make a
reference to a reference to something).

The solution I came up with it's pretty much like the one presented by
Jim Langston, but with a twist. Jim used new memory allocations, and
his idea was right in the sense of not using a statically allocated
class member. James Kanze was in this same direction, he suggested
using a constructor which received a "char *" as a parameter, thus
using externally allocated data.

Borrowing ideas from the "copy on write" mechanism of some strings
implementations, I came up with a solution which I think can be
extended to any functor instance which can hold permanent state data.

Here is the code:

-------------------------------------------------------------------
#include <functional>
#include <string>
#include <iostream>

using namespace std;

struct space_compactor : public unary_function<char, bool> {

private:
mutable bool m_data;
bool & m_lastIsSpace;

public:
// Default constructor. Initialize m_lastIsSpace to
// use m_data as the reference
space_compactor()
: m_lastIsSpace(m_data)
{
// We begin with "lastIsSpace == true" so as to erase
// the very first spaces. (Effectively doing a ltrim)
m_lastIsSpace = true;
}

// Copy constructor. Used in function arguments passed by
// value. Initialize m_lastIsSpace in this case as a
// reference of m_date of the original object.
space_compactor(const space_compactor &src)
: m_lastIsSpace(src.m_data)
{
}

result_type operator ()(const argument_type c) const
{
bool spacePresent = ::isspace(c);
bool mustRemove = m_lastIsSpace && spacePresent;
m_lastIsSpace = spacePresent;
return (result_type) mustRemove;
}

};

int main()
{
const string cad1(" this is \t a");
const string cad2(" white space compactor \n");
const string cad3(" \n \n \t functor");
string cad_out;

space_compactor instance;

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad_out),
instance );
remove_copy_if(cad2.begin(), cad2.end(), back_inserter(cad_out),
instance );
remove_copy_if(cad3.begin(), cad3.end(), back_inserter(cad_out),
instance );

cout << "[" << cad_out << "]" << endl;

return 0;
}
-------------------------------------------------------------------

The output of this little program is:

[this is a white space compactor functor]

So it works ok. No memory allocations, no static members, etc.

Cheers,
Dijkstra.
 
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
template copy constructor vs normal copy constructor cinsk C++ 35 10-10-2010 11:14 PM
Return value of functor object in for_each algorithm mthread C++ 4 06-01-2009 10:58 AM
A constructor calling another constructor (default constructor)? Generic Usenet Account C++ 10 11-28-2007 04:12 AM
Ordinary unary function to STL adaptable unary predicate how? SpOiLeR C++ 10 10-19-2005 01:18 PM
Help with functor/template/constructor jack C++ 3 02-28-2004 04:18 PM



Advertisments