By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,084 Members | 1,261 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,084 IT Pros & Developers. It's quick & easy.

Unary functor on algorithm using copy constructor

P: n/a
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
Share this Question
Share on Google+
11 Replies


P: n/a

"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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a

"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

P: n/a
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

P: n/a
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

P: n/a
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

P: n/a
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 discussion thread is closed

Replies have been disabled for this discussion.