473,480 Members | 1,873 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Unary functor on algorithm using copy constructor

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,
Jul 8 '08 #1
11 2257

"Dijkstra" <pe*****@gmail.comwrote in message
news:6b**********************************@k30g2000 hse.googlegroups.com...
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,

Jul 8 '08 #2
Jim Langston wrote:
"Dijkstra" <pe*****@gmail.comwrote in message
news:6b**********************************@k30g2000 hse.googlegroups.com...
>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).
Jul 9 '08 #3
On Jul 8, 10:14*pm, "Jim Langston" <tazmas...@rocketmail.comwrote:
"Dijkstra" <pepi...@gmail.comwrote in message

news:6b**********************************@k30g2000 hse.googlegroups.com...
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.
Jul 9 '08 #4
On Jul 8, 9:50*pm, Dijkstra <pepi...@gmail.comwrote:
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" <tazmas...@rocketmail.comwrote:
"Dijkstra" <pepi...@gmail.comwrote in message

news:6b**********************************@k30g2000 hse.googlegroups.com...
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.
Jul 9 '08 #5
Hi Jim!

On Jul 8, 7:14*pm, "Jim Langston" <tazmas...@rocketmail.comwrote:
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.
Jul 9 '08 #6
Hi red!

On Jul 9, 5:48*am, red floyd <no.spam.h...@example.comwrote:
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.
Jul 9 '08 #7

"Dijkstra" <pe*****@gmail.comwrote in message
news:67**********************************@m3g2000h sc.googlegroups.com...
Hi Jim!

On Jul 8, 7:14 pm, "Jim Langston" <tazmas...@rocketmail.comwrote:
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;
}
Jul 9 '08 #8
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.
Jul 9 '08 #9
On Jul 10, 1:09 am, Dijkstra <pepi...@gmail.comwrote:
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.
Which could be on the stack. And which could be initialized
however you wanted.

[...]
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)
{
}
I considered this solution as well, but somehow, it seemed a bit
too subtle. Every instance has an m_data, but only the original
one is used. It runs into problems as well if for some reason,
a copy outlives the originating instance (which, of course,
won't happen if it's only used as a predicate). By having the
user provide the actual data element, you've shoved the
responsibility for the lifetime off onto him:-). (The most
robust solution, of course, is dynamic allocation and a
boost::shared_ptr in the implementation. There's something
about dynamically allocating a single bool which gets my hackles
up, however, and when you throw in the added complexity of a
smart pointer on top of that, all for just one little bit...)

I also tend to use a pointer instead of a reference in the
class object, since doing so makes the class assignable, and not
just copiable. I don't think that this is a requirement, but
somehow, it just seems more natural to me that the two go
together. Just a personal preference, I guess.

--
James Kanze (GABI Software) email:ja*********@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
Jul 10 '08 #10
Hi there,

On Jul 10, 11:19*am, James Kanze <james.ka...@gmail.comwrote:
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.

Which could be on the stack. *And which could be initialized
however you wanted.
Agreed, and I don't dislike this mechanism. The only problem is that
this complexity is for a single damned f**king bool. :-)

I foresee a possible predicate class which could store more complex
state information. This is the perfect scenario for a external state
class. Perhaps "class persistent_state" which could work in
cooperation with "class persistent_predicate".
* * // 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)
* * {
* * }

I considered this solution as well, but somehow, it seemed a bit
too subtle. *Every instance has an m_data, but only the original
one is used. *It runs into problems as well if for some reason,
a copy outlives the originating instance (which, of course,
won't happen if it's only used as a predicate).
Again, you're right. The m_data instance is a problem, a "resource
leak" if you like.

I will elaborate this and the idea of the shared_ptr deeply. I really
like the idea of the "persistent_predicate" above. :-) Now it's only a
bool, but one can think of more complicated states (a stack of
strings, for example).

Cheers,
Dijkstra.
Jul 10 '08 #11
On Jul 10, 1:09*am, Dijkstra <pepi...@gmail.comwrote:
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:
<snip>

What about tr1::bind?

#include <tr1/functional>
#include <string>
#include <iostream>

using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;

int main()
{

struct trimmer { static bool _(bool &lastIsSpace, const char c)
{
bool spacePresent = ::isspace(c);
bool mustRemove = lastIsSpace && spacePresent;
lastIsSpace = spacePresent;
return mustRemove;
} };

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

bool lastIsSpace = true;

remove_copy_if(cad1.begin(), cad1.end(), back_inserter(cad_out),
bind(&trimmer::_, ref(lastIsSpace), _1) );
remove_copy_if(cad2.begin(), cad2.end(), back_inserter(cad_out),
bind(&trimmer::_, ref(lastIsSpace), _1) );
remove_copy_if(cad3.begin(), cad3.end(), back_inserter(cad_out),
bind(&trimmer::_, ref(lastIsSpace), _1) );

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

return 0;
}
Jul 10 '08 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
4649
by: Alex Vinokur | last post by:
Functor-parameters in the for_each() and transform() algorithms are passed by value. Might it make sense to have also algorithms for_each2() and transform2() which pass Functor-parameters by...
2
2238
by: Fred Ma | last post by:
Hello, I have a random generator that takes a scaling factor as an argument. Since it takes one argument, it is not a generator in the sense defined by SGI's online STL documentation. I'd...
3
2054
by: jack | last post by:
Hi there, I have a function F(x, y, z) and I want to calculate f(a) + f(b), where f(x) = F(x, x, z0) z0 is fixed. Suppose somebody wrote a routine called "Compute" which simply computes f(a)...
4
2888
by: daniel.w.gelder | last post by:
I wrote a template class that takes a function prototype and lets you store and call a C-level function, like this: inline string SampleFunction(int, bool) {..} functor<string (int, bool)>...
10
4628
by: SpOiLeR | last post by:
I have function bool IsGood (const std::string& sr); I want to use that function in std::not1 STL functor. I tried this: not1(IsGood) /* error : 'std::unary_negate<_Fn1> std::not1(const...
5
5465
by: Marcin Gil | last post by:
Hi! I have the code like this (obvious things like ctor/dtor removed) typedef struct _NODE { int val; int index; } Node;
5
2508
by: Fei Liu | last post by:
Hello, I have a situation where I need to design a library for multi-thread application, each thread does some work in a client supplied std::ptr_fun(free_function) or a functor. Now since it's...
1
2791
by: BSand0764 | last post by:
I'm getting an error that I can't seem to resolve. When I compile the Functor related logic in a test program, the files compile and execute properly (see Listing #1). However, when I...
2
2267
by: aaragon | last post by:
Hi guys, Is there a way to return a functor from a recursive call that takes different paths? Let's say that I have a tree structure like: root | first child ---- nextSibling ----nextSibling...
0
6908
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7043
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7081
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
6921
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
1
4776
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4481
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
2984
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1300
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
179
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.