Some questions about final review

1. which of the following is a valid function call?
void tryout(int, char, int&, float&); //function prototype
int a=4, b=0;//variable declarations
float y;
char c;

a. tryout(3, 'a', 5,y);
b. tryout(a,c,a*b,y);
c. tryout (8, 't', b,7.8);
d. tryout(a+b,'b',b,y);
answer:d
2. which of the following is a valid function call?
void compute(int, float, char&, int&); //function prototype
int x,y;//variable declarations
float p,q;
char r,s;
a. compute(x,7.3,'c',y);
b. compute(y,p,s,x+y);
c. compute(5,p+q,r,y);
d. compute(x,s,r,8);
answer:c
I knew if it is pass by reference, it should't have constant value. Therefore, for the first question, I eliminate option A and C,but still don't know why B is wrong. For the second, I eliminate option D because 8 is a constant, and 'c' is not existed, but don't know why B is wrong.
Well, b is wrong because look at the third variable being passed: a*b. Isn't that a constant? For the other one, wouldn't x+y be a constant?
That's another issue... Maybe I got some blind spots... I mean, if a*b equal to 0 is a constant, why d is correct? for the third variable being passed: b. Isn't it always equal to 0 as a constant?
For the other one, if x+y is a constant, I cannot nail it down why x and y not constant respectively. Again, thank you for your reply.
The reasoning is that * and + are operators that return constants. a*b is a function:

operator*(int rhs)

Essentially, a is calling a function with parameter b that returns the product of a and b. You can't fetch the address of a product, even if you have the two variables that produced it. Same goes for the sum.
Cool, get it. One last question? What if a function is pass by value? Like compute(int, float)? Are those must be constant value inside the parentheses? Or they can also be variables?
They can be variables or constants.
The reasoning is that * and + are operators that return constants. a*b is a function

This statement is not quite correct. When you assign to a variable, e.g.

c = a*b;

then operator= is being passed a anonymous temporary value, known as an rvalue, which is the result of the expression evaluated on the right (here a call to operator* to evaluate a*b). This result is not (necessarily) const.

And normal reference function parameters cannot accept rvalues.

A normal reference needs an lvalue, which is something which has a lifetime longer than the expression it appears in. (The names lvalue and rvalue started off life meaning things that could appear on the left hand or right hand side of an expression, but that's not how they're defined these days. See below...)

Edit: I think my attempt at explaining the origin of lvalue and rvalue is a bit of a failure. See references below.

I say normal here as C++11 introduced rvalue references, which have two &s, e.g. int&& is an rvalue reference to an int. If you alter tryout()'s signature to use one for its 3rd parameter, e.g.

void tryout(int, char, int&&, float&);

then

tryout(a,c,a*b,y);

will compile OK (though it's not necessarily the right thing to do!)

See below if you want further detail.

Andy

Try it out!

To see what's up in more detail try compiling the code!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

void tryout(int, char, int&, float&);
   
int main()
{
    int a=4, b=0;
    float y=3.1415f;
    char c='?';

    tryout(a,c,a*b,y);

    return 0;
}

// stub - does nothing except resolve linkage
void tryout(int, char, int&&, float&)
{
}


GCC makes two complaints:

.../main.cpp:12:17: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
.../main.cpp:4:6: error: in passing argument 3 of 'void tryout(int, char, int&, float&)'


So you can see that it doesn't like the fact that an rvalue is being passed as the 3rd parameter.

So what is an rvalue?

A quick google later ("what's an rvalue?")...

An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.

From: Lvalues and Rvalues
https://msdn.microsoft.com/en-us/library/f90831hc.aspx

And for rather more detail "see values and rvalues in C++98/03" section here:

Rvalue References: C++0x Features in VC10, Part 2
http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx

Test with rvalue

In this code I've swapped the signature to:

void tryout(int i, char c, int&& ri, float& rf);

and it compiles OK with (if you use a C++11 compliant compiler!):

tryout(a,c,a*b,y);

But note that when you run the code, which changes the int passed to the third parameter, it is just pointlessly changing the temporary value (rvalue) returned by a+b which cannot be accessed later.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <ctype.h>
using namespace std;

void tryout(int i, char c, int&& ri, float& rf); // with rvalue reference
   
int main()
{
    int a=4, b=0;
    float y=3.1415f;
    char c='x';

    cout << "[before]\n"
         << "a = " << a << "\n"
         << "b = " << b << "\n"
         << "j = " << y << "\n"
         << "c = " << c << "\n"
         << "\n";

    cout << "[call tryout]\n";
    cout << "tryout(a,c,a*b,y);\n"
         << "\n";
    tryout(a,c,a*b,y);
    cout << "\n";

    cout << "[after]\n"
         << "a = " << a << "\n"
         << "b = " << b << "\n"
         << "j = " << y << "\n"
         << "c = " << c << "\n"
         << "\n";

    return 0;
}

// stub - does nothing except resolve linkage
void tryout(int i, char c, int&& ri, float& rf)
{
    cout << "* * * ENTER TRYOUT * * *\n";

    cout << "[starting values]\n"
         << "i  = " << i  << "\n"
         << "c  = " << c  << "\n"
         << "ri = " << ri << "\n"
         << "rf = " << rf << "\n"
         << "\n";

    cout << "* * * CHANGE ALL VALUE * * *\n";
    cout << "i = " << -i << "\n";
    i = -i;
    char temp = '?';
    if(isalpha(c))
        temp = static_cast<char>(toupper(c));
    cout << "c = " << temp << "\n";
    c = temp;
    cout << "ri = " << i << "\n";
    ri = i;
    cout << "rf = " << (rf * rf) << "\n";
    rf = (rf * rf);
    cout << "\n";

    cout << "[ending values]\n"
         << "i  = " << i  << "\n"
         << "c  = " << c  << "\n"
         << "ri = " << ri << "\n"
         << "rf = " << rf << "\n"
         << "\n";

    cout << "* * * LEAVE TRYOUT * * *\n";
}


[before]
a = 4
b = 0
j = 3.1415
c = x

[call tryout]
tryout(a,c,a*b,y);

* * * ENTER TRYOUT * * *
[starting values]
i  = 4
c  = x
ri = 0
rf = 3.1415

* * * CHANGE ALL VALUE * * *
i = -4
c = X
ri = -4
rf = 9.86902

[ending values]
i  = -4
c  = X
ri = -4
rf = 9.86902

* * * LEAVE TRYOUT * * *

[after]
a = 4
b = 0
j = 9.86902
c = x

Last edited on
Topic archived. No new replies allowed.