References Question (Long)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Daniel Wilcox

    References Question (Long)

    I have a question, I have been given a piece of code that
    apparantly
    compiles under Visual C++ but I cannot get to compile under
    g++ 3.2.
    I have read the FAQ and delved into the Stroustrup book as
    well as an
    O'Reilly one but please I am not a natural C++ programmer so
    allow me
    some scope to commit some no-brainers as it were ;)

    Now looking at the code here is a simplified example of the
    problem I
    am trying to resolve:

    int f(int &x, int &y)
    {
    int local;

    // do something perverse with x & y store result in local
    return(local);
    }

    int g(int &x, int &y)
    {
    int local;

    // do something depraved with x & y store result in local
    return(local);
    }

    As I understand it passing back local variables in C++ is
    considered a
    badidea(tm), I'm not sure I fully appreciate the reasoning
    behind this
    though. Although I guess it's a functional thing and not really
    conducive to the idea of objects.

    class matrix {
    matrix::matrix( );
    matrix::matrix( int &i, int &j) {
    // do something kinky with i & j to create a matrix
    }
    };

    Then the constructor is called something like this,

    matrix M(g(a,b) + f(c+d), f(h,t) * g(o,p));

    Now this doesn't even compile throwing a "could not convert
    g(..) to
    int&" error. I understand this, to make it compile I toyed
    with the
    idea of making g and f return references, as in "int
    &g(int&...., "
    however the ungoodness of this became immediately apparent
    although it
    did compile with warnings, creating pointers in C to stack
    results
    would be considered bad form as well. Another obvious kludge
    to get it
    to work would be to store the results of the returns in the
    calling
    function and replace the parameters to the constructor as in:

    int tmp_g = g(a,b);
    int tmp_f = f(a,b);

    matrix M(tmp_g, tmp_f);

    This should work but I appreciate that again it is returning
    locals,
    however I need something working quickly, would this be
    reasonable in
    the short term? The original code allegedly works under
    Windows but
    will this be the case with Linux if modified as above, I
    understand
    this may lead to "undefined" behaviour?

    Should I bite the bullet and think about either a) re-write
    or b) get
    the guy who wrote it to redo it. I am loathe really to do
    either as I
    havn't really got time to do it or give an impromptu OO
    course to the
    author.

    The questions is why does the original even compile on MSVC
    let alone
    run? I have so far been unable to get hold of the author of
    the code
    so I only have his word that it works, but it seems strange.

    Thanks for any advice,

    Daniel.

  • Chris Dams

    #2
    Re: References Question (Long)

    Daniel Wilcox <dvw269k@yahoo. co.uk> writes:
    [color=blue]
    >int f(int &x, int &y)[/color]
    [color=blue]
    >int g(int &x, int &y)[/color]
    [color=blue]
    >class matrix {
    > matrix::matrix( );
    > matrix::matrix( int &i, int &j) {
    > // do something kinky with i & j to create a matrix
    > }
    >};[/color]
    [color=blue]
    >Then the constructor is called something like this,[/color]
    [color=blue]
    >matrix M(g(a,b) + f(c+d), f(h,t) * g(o,p));[/color]
    [color=blue]
    >Now this doesn't even compile throwing a "could not convert
    >g(..) to
    >int&" error.[/color]

    You can turn the arguments of matrix::matrix into integers instead of
    references to integers. Perhaps you should also do this to your function
    f if you want to pass c+d to it.

    Bye,
    Chris Dams

    Comment

    • Christian Jaeger

      #3
      Re: References Question (Long)

      change "int&" to "const int&" in your declarations (for f,g,matrix,...)
      (unless you want to modify the arguments in the functions - but then
      indeed, a call like matrix(f(..),g( ..)) makes no sense).

      Comment

      • Daniel Wilcox

        #4
        Re: References Question (Long)

        Chris Dams wrote:[color=blue]
        > Daniel Wilcox <dvw269k@yahoo. co.uk> writes:
        >[color=green]
        >>matrix M(g(a,b) + f(c+d), f(h,t) * g(o,p));[/color]
        >
        >[color=green]
        >>Now this doesn't even compile throwing a "could not convert
        >>g(..) to
        >>int&" error.[/color]
        >
        >
        > You can turn the arguments of matrix::matrix into integers instead of
        > references to integers. Perhaps you should also do this to your function
        > f if you want to pass c+d to it.
        >
        > Bye,
        > Chris Dams[/color]

        That should have been "c,d". Thanks.

        Comment

        • Karl Heinz Buchegger

          #5
          Re: References Question (Long)



          Daniel Wilcox wrote:[color=blue]
          >
          > Now looking at the code here is a simplified example of the
          > problem I
          > am trying to resolve:
          >
          > int f(int &x, int &y)
          > {
          > int local;
          >
          > // do something perverse with x & y store result in local
          > return(local);
          > }
          >
          > int g(int &x, int &y)
          > {
          > int local;
          >
          > // do something depraved with x & y store result in local
          > return(local);
          > }
          >
          > As I understand it passing back local variables in C++ is
          > considered a
          > badidea(tm)[/color]

          It is. But you are not passing back a local variable.

          IN C++ as in C, if you specify nothing special then always a copy
          of the value is passed.

          Thus in:

          void foo( int i );

          int main()
          {
          int a = 7;
          foo( a );
          }

          it is not a that is passed to foo(). It is the current value of a,
          which happens to be 7, that is passed to the function.

          Some in the other direction:

          int foo()
          {
          int local = 5;
          return local;
          }

          Since the return type of foo is int, a value is passed to the caller.
          Thus it is not local that is returned, but it is the current value
          of local, which happens to be 5, that is returned.
          [color=blue]
          >, I'm not sure I fully appreciate the reasoning
          > behind this
          > though.[/color]

          Because if you return a local variable, you do this by returning
          a reference to that local variable. But the local variable is detroyed
          at the moment the function exits. Thus the caller is left with a reference
          to a variable which no longer exists.
          [color=blue]
          > Although I guess it's a functional thing and not really
          > conducive to the idea of objects.
          >
          > class matrix {
          > matrix::matrix( );
          > matrix::matrix( int &i, int &j) {[/color]

          In case of built in types, like char, int, long, double, pass
          per reference is not of much use, if the function does not plan
          to modify the callers variable. In your case I would guess that this
          is the case, thus you can do:

          matrix::matrix( int i, int j ) {
          ...
          [color=blue]
          > // do something kinky with i & j to create a matrix
          > }
          > };
          >
          > Then the constructor is called something like this,
          >
          > matrix M(g(a,b) + f(c+d), f(h,t) * g(o,p));[/color]

          g returns an int, so does f. Those 2 ints (numbers) are added
          together and sent to the constructor. But your current constructor
          says: Hey, I want a reference! You send me some numbers, I want a variable,
          cause that is what a reference is: another name for some variable. So give
          me a variable"

          You could do

          int temp = g(a,b) + f(c+d);

          matrix M( temp, ....

          See: Now I have given the constructor what it demands: a variable, such that
          the ctor can take a reference from it.
          [color=blue]
          >
          > Now this doesn't even compile throwing a "could not convert
          > g(..) to
          > int&" error. I understand this, to make it compile I toyed
          > with the
          > idea of making g and f return references, as in "int
          > &g(int&...., "[/color]

          Bad idea.
          All you need to do, is make the ctor accept plain int instead of
          references.
          [color=blue]
          >
          > The questions is why does the original even compile on MSVC
          > let alone
          > run?[/color]

          Depends on which version that was and what service packs were installed.
          Newer versions of MSVC don't compile it.

          --
          Karl Heinz Buchegger
          kbuchegg@gascad .at

          Comment

          • Daniel Wilcox

            #6
            Re: References Question (Long)

            Karl Heinz Buchegger wrote:[color=blue]
            >
            > Daniel Wilcox wrote:
            >[color=green]
            >>class matrix {
            >> matrix::matrix( );
            >> matrix::matrix( int &i, int &j) {[/color]
            >
            >
            > In case of built in types, like char, int, long, double, pass
            > per reference is not of much use, if the function does not plan
            > to modify the callers variable. In your case I would guess that this
            > is the case, thus you can do:
            >
            > matrix::matrix( int i, int j ) {
            > ...
            >[/color]

            I simplified the arguments, there are some instances where
            matrix::matrix( int &, int&) is the case. Now I can see how
            replacing these as above would work. However there are other
            cases where matrix::matrix( matrix &) is used. In these
            cases the calls are similar to the examples such that:

            matrix f(int &r, int &c, matrix &m)
            {
            matrix ret;

            // do something

            return(ret);
            }

            followed by a call to the constructor such as:


            matrix M(f(x,y,m) * f(y,x,m));

            So here if I am correct? I could replace this with something
            like

            matrix a = f(x,y,m);
            matrix b = f(y,x,m);
            matrix M(a * b);

            which makes more sense.

            To further confuse me though the code also contains
            overloaded operators such as:

            matrix operator * (matrix& lhs, matrix& rhs)
            {
            matrix temp;

            // do some multiplication

            return (temp);
            }
            [color=blue]
            > Thus in:[/color]
            [color=blue]
            > int foo()
            > {
            > int local = 5;
            > return local;
            > }
            > Since the return type of foo is int, a value is passed to[/color]
            the caller.[color=blue]
            > Thus it is not local that is returned, but it is the[/color]
            current value[color=blue]
            > of local, which happens to be 5, that is returned.[/color]

            I understand the above example. In the case of the operator
            example when returning temp am I correct to say that this
            will not be the return of a value? Where returning local=5
            is correct returning an object is in fact the idea that is a
            bad one? Would I be correct in saying that the author seems
            to have got a bit confused with C and C++ returning
            conventions, treating returns of objects as returns of
            values as in C?

            I know its confusing me! ;)

            Thanks, Daniel.

            Comment

            • jeffc

              #7
              Re: References Question (Long)


              "Daniel Wilcox" <dvw269k@yahoo. co.uk> wrote in message
              news:bkrr96$ed1 $1@jura.cc.ic.a c.uk...[color=blue]
              >
              > // do something perverse with x & y store result in local
              > return(local);
              > }
              >
              > int g(int &x, int &y)
              > {
              > int local;
              >
              > // do something depraved with x & y store result in local
              > return(local);
              > }
              >
              > As I understand it passing back local variables in C++ is
              > considered a
              > badidea(tm), I'm not sure I fully appreciate the reasoning
              > behind this
              > though.[/color]

              No, that's not necessarily true. You're returning the *value* of the local
              int, but the actual storage used is going to be a temporary int that does
              not depend on "local" staying around permanently. If you had returned a
              *pointer* to local, then that would be bad, because the storage for local is
              gone after the function exits.

              Before we go any further, why are the parameters x and y declared as
              references?


              Comment

              • jeffc

                #8
                Re: References Question (Long)


                "Christian Jaeger" <cj@sim.bepr.et hz.ch> wrote in message
                news:3f718f8a$1 @pfaff2.ethz.ch ...[color=blue]
                > change "int&" to "const int&" in your declarations (for f,g,matrix,...)[/color]

                But that really makes no sense either. It should just be "int" in that
                case.


                Comment

                • Daniel Wilcox

                  #9
                  Re: References Question (Long)

                  jeffc wrote:[color=blue]
                  > "Daniel Wilcox" <dvw269k@yahoo. co.uk> wrote in message
                  > news:bkrr96$ed1 $1@jura.cc.ic.a c.uk...
                  >[color=green]
                  >>// do something perverse with x & y store result in local
                  >>return(local) ;
                  >>}
                  >>
                  >>int g(int &x, int &y)
                  >>{
                  >>int local;
                  >>
                  >>// do something depraved with x & y store result in local
                  >>return(local) ;
                  >>}
                  >>
                  >>As I understand it passing back local variables in C++ is
                  >>considered a
                  >>badidea(tm) , I'm not sure I fully appreciate the reasoning
                  >>behind this
                  >>though.[/color]
                  >
                  >
                  > No, that's not necessarily true. You're returning the *value* of the local
                  > int, but the actual storage used is going to be a temporary int that does
                  > not depend on "local" staying around permanently. If you had returned a
                  > *pointer* to local, then that would be bad, because the storage for local is
                  > gone after the function exits.
                  >
                  > Before we go any further, why are the parameters x and y declared as
                  > references?
                  >
                  >[/color]

                  In the actual code they are not int's but objects, I
                  realise, now, that I have not exactly been clear about this.
                  Yes I understand the passing of variables, but I think I
                  have confused myself with the passing of objects and how
                  this differs. Im going for a coffee.

                  Comment

                  • Karl Heinz Buchegger

                    #10
                    Re: References Question (Long)



                    Daniel Wilcox wrote:[color=blue]
                    >[/color]
                    [color=blue]
                    > I simplified the arguments, there are some instances where
                    > matrix::matrix( int &, int&) is the case. Now I can see how
                    > replacing these as above would work. However there are other
                    > cases where matrix::matrix( matrix &) is used. In these
                    > cases the calls are similar to the examples such that:
                    >
                    > matrix f(int &r, int &c, matrix &m)
                    > {
                    > matrix ret;
                    >
                    > // do something
                    >
                    > return(ret);
                    > }
                    >[/color]

                    I suppose the passed matrix m, is not changed. In such cases,
                    you do it, by passing a reference, but it should be a const reference:

                    matrix f( int r, int c, const matrix& m )
                    {

                    ....
                    [color=blue]
                    > followed by a call to the constructor such as:
                    >
                    > matrix M(f(x,y,m) * f(y,x,m));
                    >
                    > So here if I am correct? I could replace this with something
                    > like
                    >
                    > matrix a = f(x,y,m);
                    > matrix b = f(y,x,m);
                    > matrix M(a * b);[/color]

                    If you make the above change you could leave it at:

                    matrix M( f(x,y,m) * f(y,x,m) );


                    updated rules of thumb:
                    * builtin types (int, long, double, etc...)

                    you want the function
                    * to not be able to alter the callers variable ->
                    pass by value

                    voif foo( int i );

                    * be able to alter the callers variable ->
                    pass by reference

                    void foo( int & i );

                    * user defined class types (eg. your matrix class)

                    you want the function
                    * to not be able to alter the callers variable ->
                    pass by const reference

                    voif foo( const matrix & m );

                    * be able to alter the callers variable ->
                    pass by reference

                    void foo( matrix & m );


                    if you get a value from a function as a return value, then you
                    can feed this value into that function only, if:
                    * the function takes the argument with call by value
                    * the function takes the argument by const reference

                    What you get from the function is a temporary. And you can't bind
                    a temporary to a non const reference.

                    [color=blue]
                    > which makes more sense.
                    >
                    > To further confuse me though the code also contains
                    > overloaded operators such as:
                    >
                    > matrix operator * (matrix& lhs, matrix& rhs)
                    > {
                    > matrix temp;
                    >
                    > // do some multiplication
                    >
                    > return (temp);
                    > }[/color]

                    Here you *must* return a value and not a reference. After
                    this function returns, temp no longer exists, so accessing
                    it from outside through a returned reference would be a severe
                    error.
                    [color=blue]
                    >[color=green]
                    > > Thus in:[/color]
                    >[color=green]
                    > > int foo()
                    > > {
                    > > int local = 5;
                    > > return local;
                    > > }
                    > > Since the return type of foo is int, a value is passed to[/color]
                    > the caller.[color=green]
                    > > Thus it is not local that is returned, but it is the[/color]
                    > current value[color=green]
                    > > of local, which happens to be 5, that is returned.[/color]
                    >
                    > I understand the above example. In the case of the operator
                    > example when returning temp am I correct to say that this
                    > will not be the return of a value?[/color]

                    Other way round. It returns the value. Only the value.
                    [color=blue]
                    > Where returning local=5
                    > is correct returning an object is in fact the idea that is a
                    > bad one? Would I be correct in saying that the author seems
                    > to have got a bit confused with C and C++ returning
                    > conventions, treating returns of objects as returns of
                    > values as in C?[/color]

                    It's very simple: If you have a plain and simple data type
                    as your return type, then you return by value: a copy of
                    the variable (or the result of an expression) is made and that
                    copied value is sent back.

                    int foo()
                    {
                    return 5; // return value 5
                    }

                    int foo()
                    {
                    int i = 8;
                    return i; // look up i, and return the value you
                    // found in i
                    }

                    matrix foo()
                    {
                    matrix m;
                    return m; // look up m and return the value you found
                    // in m.
                    }

                    In all cases: After the function has returned, whatever was inside
                    that function (eg. local variables) are no longer needed, since
                    a copy of the return value has already been made and returned to
                    the caller.

                    --
                    Karl Heinz Buchegger
                    kbuchegg@gascad .at

                    Comment

                    • jeffc

                      #11
                      Re: References Question (Long)


                      "Daniel Wilcox" <dvw269k@yahoo. co.uk> wrote in message
                      news:bksapn$j6o $1@jura.cc.ic.a c.uk...[color=blue]
                      > jeffc wrote:[color=green]
                      > > "Daniel Wilcox" <dvw269k@yahoo. co.uk> wrote in message
                      > > news:bkrr96$ed1 $1@jura.cc.ic.a c.uk...[color=darkred]
                      > >>As I understand it passing back local variables in C++ is
                      > >>considered a
                      > >>badidea(tm) , I'm not sure I fully appreciate the reasoning
                      > >>behind this
                      > >>though.[/color]
                      > >
                      > >
                      > > No, that's not necessarily true. You're returning the *value* of the[/color][/color]
                      local[color=blue][color=green]
                      > > int, but the actual storage used is going to be a temporary int that[/color][/color]
                      does[color=blue][color=green]
                      > > not depend on "local" staying around permanently. If you had returned a
                      > > *pointer* to local, then that would be bad, because the storage for[/color][/color]
                      local is[color=blue][color=green]
                      > > gone after the function exits.
                      > >
                      > > Before we go any further, why are the parameters x and y declared as
                      > > references?[/color]
                      >
                      > In the actual code they are not int's but objects, I
                      > realise, now, that I have not exactly been clear about this.
                      > Yes I understand the passing of variables, but I think I
                      > have confused myself with the passing of objects and how
                      > this differs. Im going for a coffee.[/color]

                      Well, it doesn't really differ. It's just that you would only pass by
                      reference if you intended to change the value of those arguments in the
                      function. The problem here lies with your misunderstaning of what "return"
                      does with the return value of the function. Let's take a simpler example
                      because I think the bigger ones are confusing you. There's a fundamental
                      problem here. For example, do you understand this?

                      int f()
                      {
                      return 1;
                      }

                      int main()
                      {
                      int i;
                      i = f();
                      }


                      Comment

                      • Karl Heinz Buchegger

                        #12
                        Re: References Question (Long)



                        Karl Heinz Buchegger wrote:[color=blue]
                        >
                        >
                        > if you get a value from a function as a return value, then you
                        > can feed this value into that function only, if:
                        > * the function takes the argument with call by value
                        > * the function takes the argument by const reference
                        >[/color]

                        that means:

                        if - call by value - OR - call by const reference
                        Either of the 2 possibilities would be fine.
                        [color=blue]
                        > What you get from the function is a temporary. And you can't bind
                        > a temporary to a non const reference.[/color]

                        That's why the compiler barfs at your original example:
                        The function took the matrix per reference. But a temporary
                        cannot be bound to a reference. It has to be a const reference.

                        --
                        Karl Heinz Buchegger
                        kbuchegg@gascad .at

                        Comment

                        Working...