473,386 Members | 1,773 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

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.

Jul 19 '05 #1
11 1923
Daniel Wilcox <dv*****@yahoo.co.uk> writes:
int f(int &x, int &y) int g(int &x, int &y) 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.


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
Jul 19 '05 #2
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).

Jul 19 '05 #3
Chris Dams wrote:
Daniel Wilcox <dv*****@yahoo.co.uk> writes:
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.

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


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

Jul 19 '05 #4


Daniel Wilcox wrote:

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)
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.
, I'm not sure I fully appreciate the reasoning
behind this
though.
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.
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) {
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 ) {
...
// 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));
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.

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&....,"
Bad idea.
All you need to do, is make the ctor accept plain int instead of
references.

The questions is why does the original even compile on MSVC
let alone
run?


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

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 19 '05 #5
Karl Heinz Buchegger wrote:

Daniel Wilcox wrote:
class matrix {
matrix::matrix();
matrix::matrix(int &i, int &j) {

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 ) {
...


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);
}
Thus in: 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.


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.

Jul 19 '05 #6

"Daniel Wilcox" <dv*****@yahoo.co.uk> wrote in message
news:bk**********@jura.cc.ic.ac.uk...

// 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.


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?
Jul 19 '05 #7

"Christian Jaeger" <cj@sim.bepr.ethz.ch> wrote in message
news:3f********@pfaff2.ethz.ch...
change "int&" to "const int&" in your declarations (for f,g,matrix,...)


But that really makes no sense either. It should just be "int" in that
case.
Jul 19 '05 #8
jeffc wrote:
"Daniel Wilcox" <dv*****@yahoo.co.uk> wrote in message
news:bk**********@jura.cc.ic.ac.uk...
// 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.

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?


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.

Jul 19 '05 #9


Daniel Wilcox wrote:
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);
}

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 )
{

....
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);
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.

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);
}
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.
> Thus in:
> 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.


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?


Other way round. It returns the value. Only the 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?


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
kb******@gascad.at
Jul 19 '05 #10

"Daniel Wilcox" <dv*****@yahoo.co.uk> wrote in message
news:bk**********@jura.cc.ic.ac.uk...
jeffc wrote:
"Daniel Wilcox" <dv*****@yahoo.co.uk> wrote in message
news:bk**********@jura.cc.ic.ac.uk...
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.

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?


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.


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();
}
Jul 19 '05 #11


Karl Heinz Buchegger wrote:


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

that means:

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


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
kb******@gascad.at
Jul 19 '05 #12

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

Similar topics

22
by: xmp333 | last post by:
Hi All, I am trying to hide my JavaScript source. The method I chose was to keep all the important source in a password protected folder, and then use a SRC="folder/script.js" to include it...
33
by: JKop | last post by:
I understand variables/objects and pointer variables perfectly: int X = 5; int* pX = &X; *pX = 4; int** ppX = &pX:
6
by: Matthias Kaeppler | last post by:
Hello, during a discussion on a C++ internet forum, some question came up regarding references and the lifetime of the objects they alias. I can't find any clear wording on that in the draft...
6
by: Matthias Kaeppler | last post by:
Hi, I have a question regarding references, and their chance to "dangle" (if that's possible at all): Say I have a collection ob objects, and I take a reference to one of them. Now I sort...
25
by: Steve Jorgensen | last post by:
Yup, Steve's full of tips, but hey, it makes him feel important, right? Ok, here goes. I've been trying to improve encapsulation by putting code in the same object as the stuff it affects, so I...
11
by: codebloatation | last post by:
I know how to use references but i DO not get WHY they exist other than to add to the language. Are they actually needed for anything?
30
by: jeremygetsmail | last post by:
I've got an adp (Metrix.adp) with a reference to another adp (InteractSQL.adp). InteractSQL sits on a server, and is refered to by all of the clients (Metrix), which sit on the client machines...
28
by: Frederick Gotham | last post by:
When I was a beginner in C++, I struggled with the idea of references. Having learned how to use pointers first, I was hesitant to accept that references just "do their job" and that's it. Just...
3
by: DonJefe | last post by:
Does anyone have experience using project->project references in large solutions? What are the plus/minuses that you have found? Currently, we are using the binary assembly references for our...
29
by: Simon Saize | last post by:
Hi - What's the point of having references (&)? Why don't we just use pointers (*)? Thanks.
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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

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