File: references.yo

package info (click to toggle)
c%2B%2B-annotations 13.02.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,576 kB
  • sloc: cpp: 25,297; makefile: 1,523; ansic: 165; sh: 126; perl: 90; fortran: 27
file content (214 lines) | stat: -rw-r--r-- 8,476 bytes parent folder | download | duplicates (4)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
In addition to the common ways to define variables (plain variables or
pointers) bf(C++) introduces hi(reference)em(references) defining synonyms
for variables. A reference to a variable is like an em(alias); the variable
and the reference can both be used in statements involving the variable:
        verb(    int int_value;
    int &ref = int_value;)

In the above example a variable tt(int_value) is defined. Subsequently a
reference tt(ref) is defined, which (due to its initialization) refers to the
same memory location as tt(int_value). In the definition of tt(ref), the
i(reference operator) hi(operator&) tt(&) indicates that tt(ref) is not
itself an tt(int) but a reference to one. The two statements
        verb(    ++int_value;
    ++ref;)

have the same effect: they increment tt(int_value)'s value.  Whether that
location is called tt(int_value) or tt(ref) does not matter.

    References serve an important function in bf(C++) as a means to pass
modifiable arguments to functions. E.g., in standard bf(C), a function that
increases the value of its argument by five and returning nothing needs a
pointer parameter:
        verb(    void increase(int *valp)    // expects a pointer
    {                           // to an int
        *valp += 5;
    }

    int main()
    {
        int x;

        increase(&x);           // pass x's address
    })

This construction can em(also) be used in bf(C++) but the same effect
is also achieved using a reference:
        verb(    void increase(int &valr)    // expects a reference
    {                           // to an int
        valr += 5;
    }

    int main()
    {
        int x;

        increase(x);            // passed as reference
    })

It is arguable whether code such as the above should be preferred over
bf(C)'s method, though. The statement tt(increase) tt((x)) suggests that not
tt(x) itself but a em(copy) is passed. Yet the value of tt(x) changes because
of the way tt(increase()) is defined. However, references can also be used to
pass objects that are only inspected (without the need for a copy or a const
*) or to pass objects whose modification is an accepted side-effect of their
use. In those cases using references are strongly preferred over existing
alternatives like copy by value or passing pointers.

    Behind the scenes references are implemented using pointers. So, as far as
the compiler is concerned references in bf(C++) are just const pointers.  With
references, however, the programmer does not need to know or to bother about
levels of indirection. An important distinction between plain pointers and
references is of course that with references no indirection takes place. For
example:
        verb(    extern int *ip;
    extern int &ir;

    ip = 0;     // reassigns ip, now a 0-pointer
    ir = 0;     // ir unchanged, the int variable it refers to
                // is now 0.)

In order to prevent confusion, we suggest to adhere to the following:
    itemization(
    it() In those situations where a function does not alter its
parameters of a built-in or pointer type, value parameters can be used:
        verb(void some_func(int val)
{
    cout << val << '\n';
}

int main()
{
    int x;

    some_func(x);       // a copy is passed
})

it() When a function explicitly must change the values of its arguments, a
pointer parameter is preferred. These pointer parameters should preferably be
the function's initial parameters. This is called emi(return by argument).
        verb(void by_pointer(int *valp)
{
    *valp += 5;
})

it() When a function doesn't change the value of its class- or struct-type
arguments, or if the modification of the argument is a trivial side-effect
(e.g., the argument is a stream) references can be used. Const-references
should be used if the function does not modify the argument:
        verb(void by_reference(string const &str)
{
    cout << str;    // no modification of str
}

int main ()
{
    int x = 7;
    by_pointer(&x);         // a pointer is passed
                            // x might be changed
    string str("hello");
    by_reference(str);      // str is not altered
})

References play an important role in cases where the argument is not
changed by the function but where it is undesirable to copy the argument to
initialize the parameter. Such a situation occurs when a large object is
passed as argument, or is returned by the function.  In these cases the
copying operation tends to become a significant factor, as the entire
object must be copied. In these cases references are preferred.

    If the argument isn't modified by the function, or if the caller shouldn't
modify the returned information, the tt(const) keyword should be
used. Consider the following example:
        verb(struct Person                   // some large structure
{
    char    name[80];
    char    address[90];
    double  salary;
};

Person person[50];          // database of persons

                            // printperson expects a
                            // reference to a structure
                            // but won't change it
void printperson (Person const &subject)
{
    cout << "Name: " << subject.name << '\n' <<
            "Address: " << subject.address << '\n';

}
                            // get a person by index value
Person const &personIdx(int index)
{
    return person[index];   // a reference is returned,
}                           // not a copy of person[index]

int main()
{
    Person boss;

    printperson(boss);      // no pointer is passed,
                            // so `boss' won't be
                            // altered by the function
    printperson(personIdx(5));
                            // references, not copies
                            // are passed here
})

it() Furthermore, note that there is yet another reason for using
references when passing objects as function arguments. When passing a
reference to an object, the activation of a so called em(copy constructor)
is avoided. Copy constructors are covered in chapter ref(MEMORY).
    )

    References em(could) result in extremely `ugly' code. A function may
return a reference to a variable, as in the following example:
        verb(    int &func()
    {
        static int value;
        return value;
    })

This allows the use of the following constructions:
        verb(    func() = 20;
    func() += func();)

It is probably superfluous to note that such constructions should normally
not be used. Nonetheless, there are situations where it is useful to return a
reference.  We have actually already seen an example of this phenomenon in our
previous discussion of streams. In a statement like tt(cout) lshift()
tt("Hello") lshift() tt('\n';) the insertion operator returns a reference to
tt(cout). So, in this statement first the tt("Hello") is inserted into
tt(cout), producing a reference to tt(cout). Through this reference the
tt('\n') is then inserted in the tt(cout) object, again producing a reference
to tt(cout), which is then ignored.

Several differences between pointers and references are pointed out in the
next list below:
    itemization(
    it() A reference cannot exist by itself, i.e., without something to
refer to. A declaration of a reference like
        center(tt(int &ref;))
    is not allowed; what would tt(ref) refer to?
    it() References can be declared as tt(external).  These references were
initialized elsewhere.
    it() References may exist as parameters of functions: they are initialized
when the function is called.
    it() References may be used in the return types of functions. In those
cases the function determines what the return value refers to.
    it() References may be used as data members of classes. We return
to this usage later.
    it() Pointers are variables by themselves. They point at
something concrete or just ``at nothing''.
    it() References are aliases for other variables and cannot be re-aliased
to another variable. Once a reference is defined, it refers to its particular
variable.
    it() Pointers (except for const pointers) can be reassigned to point to
different variables.
    it() When an i(address-of operator) hi(operator&) ti(&) is used with a
reference, the expression yields the address of the variable to which the
reference applies. In contrast, ordinary pointers are variables themselves, so
the address of a pointer variable has nothing to do with the address of the
variable pointed to.
    )