Problem with own global operator+

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Emanuel Ziegler

    Problem with own global operator+

    Hello,

    I want to do some mathematics with functions. In my case the function
    classes are very complex, but this simple example has the same problems.

    To allow calculations that begin with a double, I have to define a global
    operator+ (or -*/) and special function classes.

    --- source begins here ---

    #include <iostream>
    using namespace std;

    class function {
    // private:
    // function *f;
    public:
    function (function *F = 0) {
    cout << "constructo r" << endl;
    // f = F;
    }
    virtual ~function () {
    cout << "destructor " << endl;
    // delete f;
    }
    virtual double operator() (double x) {
    // if ( f == 0 )
    cout << "ERROR!" << endl;
    // else
    // return (*f)(x);
    };
    };
    class identity : public function{
    public:
    virtual double operator() (double x) { return x; }
    };
    class sum : public function {
    private:
    double a;
    function *b;
    public:
    sum (double A, function &B) : function() { a = A; b = &B; }
    virtual double operator() (double x) { return a+(*b)(x); }
    };

    function & operator+ (double x, function &B) {
    return *new sum(x,B);
    }

    int main () {
    identity id;
    cout << (1+id)(1) << endl;
    cout << (1+(1+id))(1) << endl; // comment out for case 3
    return 0;
    }

    --- source ends here ---

    There are three cases:
    (1) Run the program as it is. You should get:

    constructor
    constructor
    2
    constructor
    constructor
    3
    destructor

    As you can see, this creates memory leaks!

    (2) Comment out all lines in the declaration of function and
    change the definition of operator + to

    function operator+ ...
    return new ...

    i.e. remove the first & in the first line and the * in the second line
    of the definition.

    This program will _not_ compile! On g++ I get

    src/prog/testfunc.cpp: In function `int main()':
    src/prog/testfunc.cpp:43 : error: no match for 'operator+' in '1 +
    operator+(doubl e, function&)((&id ))'
    src/prog/testfunc.cpp:36 : error: candidates are: function operator
    +(double,functi on&)

    I have no problems with member operators doing calculations like
    (function+1)+2
    it's only the global operators!

    (3) Same as in case 2, but also comment out the marked line in case 3 and
    you should get

    constructor
    constructor
    constructor
    2
    destructor
    destructor
    destructor

    My questions are now:
    1. Does anybody know a better solution than case 3 for avoiding memory
    leaks?
    2. If not, how can I get case 2 to work (without changing int main(),
    of course)?


    Thanks in advance
    Emanuel

  • Emanuel Ziegler

    #2
    Re: Problem with own global operator+

    Emanuel Ziegler wrote:[color=blue]
    > (2) Comment out all lines in the declaration of function and
    > change the definition of operator + to[/color]

    Of course, you must remove the comments in the declaration of function.

    Sorry
    Emanuel

    Comment

    • Rolf Magnus

      #3
      Re: Problem with own global operator+

      Emanuel Ziegler wrote:
      [color=blue]
      > Hello,
      >
      > I want to do some mathematics with functions. In my case the function
      > classes are very complex, but this simple example has the same
      > problems.
      >
      > To allow calculations that begin with a double, I have to define a
      > global operator+ (or -*/) and special function classes.
      >
      > --- source begins here ---
      >
      > #include <iostream>
      > using namespace std;
      >
      > class function {
      > // private:
      > // function *f;
      > public:
      > function (function *F = 0) {
      > cout << "constructo r" << endl;
      > // f = F;
      > }
      > virtual ~function () {
      > cout << "destructor " << endl;
      > // delete f;
      > }
      > virtual double operator() (double x) {
      > // if ( f == 0 )
      > cout << "ERROR!" << endl;
      > // else
      > // return (*f)(x);
      > };
      > };
      > class identity : public function{
      > public:
      > virtual double operator() (double x) { return x; }
      > };
      > class sum : public function {
      > private:
      > double a;
      > function *b;
      > public:
      > sum (double A, function &B) : function() { a = A; b =
      > &B; }
      > virtual double operator() (double x) { return
      > a+(*b)(x); }
      > };
      >
      > function & operator+ (double x, function &B) {
      > return *new sum(x,B);[/color]

      Very bad idea. Who deletes the created object? You should never return
      references to dynamically allocated memory. Why don't you simply return
      by valu anyway?
      [color=blue]
      > }
      >
      > int main () {
      > identity id;
      > cout << (1+id)(1) << endl;
      > cout << (1+(1+id))(1) << endl; // comment out for case 3
      > return 0;
      > }
      >
      > --- source ends here ---
      >
      > There are three cases:
      > (1) Run the program as it is. You should get:
      >
      > constructor
      > constructor
      > 2
      > constructor
      > constructor
      > 3
      > destructor
      >
      > As you can see, this creates memory leaks![/color]

      Yes. The reason is that you allocate objects with new, but never delete
      them.
      [color=blue]
      > (2) Comment out all lines in the declaration of function and
      > change the definition of operator + to
      >
      > function operator+ ...
      > return new ...
      >
      > i.e. remove the first & in the first line and the * in the
      > second line of the definition.[/color]

      Again, you should _not_ use new at all. Is it possible that you are
      coming from a Java backround? Proper usage of new in C++ is completely
      different from Java.
      [color=blue]
      > This program will _not_ compile! On g++ I get
      >
      > src/prog/testfunc.cpp: In function `int main()':
      > src/prog/testfunc.cpp:43 : error: no match for 'operator+' in '1
      > +
      > operator+(doubl e, function&)((&id ))'
      > src/prog/testfunc.cpp:36 : error: candidates are: function
      > operator
      > +(double,functi on&)
      >
      > I have no problems with member operators doing calculations like
      > (function+1)+2
      > it's only the global operators![/color]

      The result of (function+1) is a temporary, and you can't bind non-const
      references to temporaries in C++. When you don't modify the parameter,
      make it a const reference. I think that's your problem here.
      [color=blue]
      > (3) Same as in case 2, but also comment out the marked line in case
      > 3 and
      > you should get
      >
      > constructor
      > constructor
      > constructor
      > 2
      > destructor
      > destructor
      > destructor
      >
      > My questions are now:
      > 1. Does anybody know a better solution than case 3 for avoiding
      > memory leaks?
      > 2. If not, how can I get case 2 to work (without changing int
      > main(),
      > of course)?
      >
      >
      > Thanks in advance
      > Emanuel[/color]

      --
      "Have you got an extra goto 10 line?"
      (from Futurama)

      Comment

      • Emanuel Ziegler

        #4
        Re: Problem with own global operator+

        Rolf Magnus wrote:[color=blue][color=green]
        >> function & operator+ (double x, function &B) {
        >> return *new sum(x,B);[/color]
        >
        > Very bad idea. Who deletes the created object? You should never return
        > references to dynamically allocated memory. Why don't you simply return
        > by valu anyway?[/color]

        I get an error message, when returning "sum(x,B)", because it's (obviously)
        temporary.

        A correct return by value, using "function operator+ ..." and "return
        sum(x,B);" is also impossible, since "sum" enhances "function" and an
        assignment "function" = "sum" would need a typecasting constructor. But
        1. I cannot create a typecasting constructor, since "sum" is defined
        later and therefore not known to the compiler when defining "function".
        2. The compiler wouldn't reserve enough space to store the private
        pointers of "sum".
        [color=blue][color=green]
        >> As you can see, this creates memory leaks![/color]
        >
        > Yes. The reason is that you allocate objects with new, but never delete
        > them.[/color]

        I know. That's why I implemented case 2. A garbage collector is a very good
        invention, but unfortunately not known to c++. That's the reason for the
        complicated definition of "function" with the "delete" line in the
        destructor.
        [color=blue][color=green]
        >> function operator+ ...
        >> return new ...[/color]
        > Again, you should _not_ use new at all. Is it possible that you are
        > coming from a Java backround?[/color]

        Parts of Java and Object Pascal. From the latter I'm used to deleting
        objects created with "new". See the reasons for "new" above.
        [color=blue][color=green]
        >> I have no problems with member operators doing calculations like
        >> (function+1)+2
        >> it's only the global operators![/color]
        >
        > The result of (function+1) is a temporary, and you can't bind non-const
        > references to temporaries in C++. When you don't modify the parameter,
        > make it a const reference. I think that's your problem here.[/color]

        Making the parameter constant does not solve the problem, because I have to
        make the second parameter of the "sum"-constructor constant. Then I have to
        make the pointer "b" inside "sum" constant. Finally, I cannot call
        operator() of "*b".

        Emanuel

        Comment

        • Alberto Barbati

          #5
          Re: Problem with own global operator+

          Emanuel Ziegler wrote:[color=blue]
          > A correct return by value, using "function operator+ ..." and "return
          > sum(x,B);" is also impossible, since "sum" enhances "function" and an
          > assignment "function" = "sum" would need a typecasting constructor. But
          > 1. I cannot create a typecasting constructor, since "sum" is defined
          > later and therefore not known to the compiler when defining "function".
          > 2. The compiler wouldn't reserve enough space to store the private
          > pointers of "sum".[/color]

          You have clearly identified the source of the problem. By inheriting sum
          from function you can no longer use function by-value.

          What I suggest is to make function a proxy class and to make a separate
          inheritance tree for functions. Like this:

          class function_base {
          private:
          virtual ~function ()
          { }

          virtual double operator() (double x) = 0; // virtual pure
          };

          class function {
          private:
          boost::shared_p tr<function_bas e> f;

          public:
          explicit function (function_base *F) // explicit is safer
          : f(F)
          {}

          // no destructor needed, as boost::shared_p tr calls delete

          double operator() (double x) const // notice this is const!!
          {
          return (*f)(x);
          }
          };

          boost::shared_p tr is a reference counter smart pointer class
          <http://www.boost.org/libs/smart_ptr/smart_ptr.htm>. you can use any
          other smart pointer class of your choice but *not* std::auto_ptr,
          otherwise function would not copiable.

          Now you derive sum from function_base (*not* function):

          class sum : public function_base {
          private:
          double a;
          function b; // by value

          public:
          sum (double A, const function& B) : a(A), b(B) {}
          virtual double operator() (double x) { return a+b(x); }
          };

          and write your operator+ as:

          function operator+ (double x, const function& B) {
          return function(new sum(x, B));
          }

          notice that return is now by value. The parameter B could have been
          passed by value insted of by const& as function has correct
          value-semantic and not very expensive to copy.
          [color=blue][color=green][color=darkred]
          >>> I have no problems with member operators doing calculations like
          >>> (function+1)+2
          >>> it's only the global operators![/color]
          >>
          >>The result of (function+1) is a temporary, and you can't bind non-const
          >>references to temporaries in C++. When you don't modify the parameter,
          >>make it a const reference. I think that's your problem here.[/color]
          >
          >
          > Making the parameter constant does not solve the problem, because I have to
          > make the second parameter of the "sum"-constructor constant. Then I have to
          > make the pointer "b" inside "sum" constant. Finally, I cannot call
          > operator() of "*b".[/color]

          My approach works around the problem. The temporary (of type function)
          is constant but you *can* invoke function::opera tor() that is now
          declared const. BTW, are you sure it won't be better to declare
          function_base:: operator() const as well?

          My €0.01

          Alberto Barbati

          Comment

          • Emanuel Ziegler

            #6
            Re: Problem with own global operator+

            Alberto Barbati wrote:[color=blue]
            > What I suggest is to make function a proxy class and to make a separate
            > inheritance tree for functions. Like this:[/color]

            This doen't work, either, as I will explain below. I made some corrections
            that are not listed here, because they are not relevant for the problem.
            See source below for details.
            [color=blue]
            > class function {
            > ...
            > double operator() (double x) const // notice this is const!![/color]

            This is the critical part. It is impossible to overwrite operator() for some
            reason. Why does g++ behave like this?
            [color=blue]
            > ...
            > function b; // by value[/color]

            Here the compiler fails, since the abstract operator() has not been
            overwritten. Thus, instances cannot be created.
            [color=blue]
            > My approach works around the problem. The temporary (of type function)
            > is constant but you *can* invoke function::opera tor() that is now
            > declared const. BTW, are you sure it won't be better to declare
            > function_base:: operator() const as well?[/color]

            Making function_base:: operator() constant does not solve the problem,
            either. Although, it is impossible to compile the code without doing this.
            With this correction and making operator() non-abstract, I can compile, but
            not execute the program.

            Here's my corrected source (execution may *crash* on some machines):

            --- source begins here ---

            #include <iostream>
            #include <boost/shared_ptr.hpp>
            using namespace std;

            class function_base {
            public:
            virtual ~function_base () {}
            // My version:
            virtual double operator() (double x) const {};
            // Version proposed by Alberto Barbati:
            // virtual double operator() (double x) = 0;
            };
            class function : public function_base {
            private:
            boost::shared_p tr<const function_base> f;
            public:
            function (const function_base *F) : f(F) {}
            virtual double operator() (double x) {
            return (*f)(x);
            }
            };
            class identity : public function_base {
            public:
            virtual double operator() (double x) { return x; }
            };
            class sum : public function_base {
            private:
            double a;
            function b;
            public:
            sum (double A, const function_base &B)
            : function_base() , a(A), b(&B) {}
            virtual double operator() (double x) { return a+b(x); }
            };

            function operator+ (double x, const function_base &B) {
            return function(new sum(x,B));
            }

            int main () {
            identity id;
            cout << (1+id)(1) << endl;
            return 0;
            }

            --- source ends here ---

            The output is

            nan
            memory protection fault

            The first line indicates, that operator() has not been overwritten (no
            return statement in original version). The second one doesn't look better.

            Emanuel

            Comment

            • Alberto Barbati

              #7
              Re: Problem with own global operator+

              Emanuel Ziegler wrote:[color=blue][color=green]
              >>class function {
              >>...
              >> double operator() (double x) const // notice this is const!![/color]
              >
              >
              > This is the critical part. It is impossible to overwrite operator() for some
              > reason. Why does g++ behave like this?[/color]

              Could you please give more details (for example giving the exact error
              message) why g++ would not want you to override operator+()?
              [color=blue][color=green]
              >>...
              >> function b; // by value[/color]
              >
              >
              > Here the compiler fails, since the abstract operator() has not been
              > overwritten. Thus, instances cannot be created.[/color]

              operator() is not virtual in my suggestion, it need not and should not
              be virtual.
              [color=blue]
              > Here's my corrected source (execution may *crash* on some machines):[/color]

              Your "corrected" source??? You disrupted the source! Class function
              should *NOT* derive from function_base. That's why you are having
              problems! Why did you do that?
              [color=blue]
              > class sum : public function_base {
              > [...]
              > sum (double A, const function_base &B)
              > : function_base() , a(A), b(&B) {}
              > [...]
              > };
              >
              > function operator+ (double x, const function_base &B) {
              > return function(new sum(x,B));
              > }[/color]

              in both cases the parameter should be of type const function&, not const
              function_base&.

              Alberto

              Comment

              • Emanuel Ziegler

                #8
                Re: Problem with own global operator+

                Alberto Barbati wrote:[color=blue]
                > Your "corrected" source??? You disrupted the source! Class function
                > should *NOT* derive from function_base. That's why you are having
                > problems! Why did you do that?[/color]

                Uuh, stupid me! Sorry, but I overread this important point in your source.
                Of course, the source didn't compile when deriving function from
                function_base. This was the reason for my unnecessary "correction s".

                Now, I got it working. Anyway, I still don't understand c++'s behaviour with
                the other source.

                Thanks a lot!
                Emanuel

                Comment

                Working...