Unary functor on algorithm using copy constructor

Discussion in 'C++' started by Dijkstra, Jul 8, 2008.

  1. Dijkstra

    Dijkstra Guest

    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,
     
    Dijkstra, Jul 8, 2008
    #1
    1. Advertising

  2. Dijkstra

    Jim Langston Guest

    "Dijkstra" <> wrote in message
    news:...
    > 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,
     
    Jim Langston, Jul 8, 2008
    #2
    1. Advertising

  3. Dijkstra

    red floyd Guest

    Identifiers (was Re: Unary functor on algorithm using copy constructor_

    Jim Langston wrote:
    > "Dijkstra" <> wrote in message
    > news:...
    >> 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).
     
    red floyd, Jul 9, 2008
    #3
  4. Dijkstra

    Vishesh Guest

    On Jul 8, 10:14 pm, "Jim Langston" <> wrote:
    > "Dijkstra" <> wrote in message
    >
    > news:...
    >
    > > 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.
     
    Vishesh, Jul 9, 2008
    #4
  5. Dijkstra

    Vishesh Guest

    On Jul 8, 9:50 pm, Dijkstra <> 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" <> wrote:
    > "Dijkstra" <> wrote in message
    >
    > news:...
    >
    > > 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.
     
    Vishesh, Jul 9, 2008
    #5
  6. Dijkstra

    James Kanze Guest

    On Jul 8, 6:50 pm, Dijkstra <> 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:
    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
     
    James Kanze, Jul 9, 2008
    #6
  7. Dijkstra

    Dijkstra Guest

    Hi Jim!

    On Jul 8, 7:14 pm, "Jim Langston" <> 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.
     
    Dijkstra, Jul 9, 2008
    #7
  8. Dijkstra

    Dijkstra Guest

    Re: Identifiers (was Re: Unary functor on algorithm using copyconstructor_

    Hi red!

    On Jul 9, 5:48 am, red floyd <> 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.
     
    Dijkstra, Jul 9, 2008
    #8
  9. Dijkstra

    Jim Langston Guest

    "Dijkstra" <> wrote in message
    news:...
    Hi Jim!

    On Jul 8, 7:14 pm, "Jim Langston" <> 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;
    }
     
    Jim Langston, Jul 9, 2008
    #9
  10. Dijkstra

    Dijkstra Guest

    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.
     
    Dijkstra, Jul 10, 2008
    #10
  11. Dijkstra

    James Kanze Guest

    On Jul 10, 1:09 am, Dijkstra <> wrote:

    > 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:
    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
     
    James Kanze, Jul 10, 2008
    #11
  12. Dijkstra

    Dijkstra Guest

    Hi there,

    On Jul 10, 11:19 am, James Kanze <> wrote:

    > > 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.
     
    Dijkstra, Jul 10, 2008
    #12
  13. Dijkstra

    gpderetta Guest

    On Jul 10, 1:09 am, Dijkstra <> wrote:
    > 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;
    }
     
    gpderetta, Jul 10, 2008
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jack
    Replies:
    3
    Views:
    404
    Victor Bazarov
    Feb 28, 2004
  2. SpOiLeR
    Replies:
    10
    Views:
    811
    SpOiLeR
    Oct 19, 2005
  3. vsgdp
    Replies:
    1
    Views:
    313
    Thomas Tutone
    Sep 26, 2006
  4. mthread
    Replies:
    4
    Views:
    461
    James Kanze
    Jun 1, 2009
  5. cinsk
    Replies:
    35
    Views:
    2,613
    James Kanze
    Oct 11, 2010
Loading...

Share This Page