More Effective C++ 翻譯沒經著者同意,翻譯及原文僅供學習交流使用
Item 1:指針輿引用的區別
指針輿引用看起來有很大區別(指針用"*"和"->"操作符,引用用"."操作符),
但是它們似乎做相似的事情.指針和引用都讓你間接指向其它對象.然而,你真的能
決定何時使用其中一個而不是另外一個?
首先,應該認識到沒有一個空引用.一個引用必須總是指向某一對象.結果,如果
你有一個變量它的目的指向另一對象,但是有可能沒有一個對象用來指向,你應該使
該變量成為指針,因為你可以置它為空.另外一方面,如果變量必須總是指向一個對象,
也就是,如果你的設計不允許一個變量為空,你或許應該使變量為引用.
"但是,",你想知道,“象下面又有怎樣的秘密?"
char *pc = 0; //設指針為空
char& rc = *pc //使引用指向
//空指針
唔,這可是麻煩的,完全的并且易受騙的.結果是不確定的(編譯器能產生輸出來做
它喜歡做的任何事情),任何寫這種代碼的人應該避免掉除非他們同意終止這樣做.如果
你擔心在你的軟件存在這種事,你最好完全避免使用引用,或者挑選一個更好的程序員來
工作.因此我們可以忽略引用是"空"的可能性.
因為引用必須指向一個對象,所以C++要求引用必須初始化:
string& rs //錯誤,引用必須
//被初始化
string s("xyzzy");
string& rs = s; //正確,rs指向s
指針就沒有這種限制:
string *ps //沒有初始化的指針:
//正確但是冒險
沒有一個空引用的事實意味著使用引用比使用指針更有效.那是因為在使用一個
引用之前沒有必要測試它的有效性:
void printDouble(const double& rd)
{
cout<<rd; //不需要測試rd,它
} //必定指向一個double
相反,指針一般說來應該被測試以防它為空:
void printDouble(const double *pd)
{
if (pd) {
cout << *pd; //為空指針作檢測
}
}
指針和引用另外一個重要的不同是指針可以可以重新分配以指向不同的對象.
然而引用總是指向它初始化指向的對象:
string s1("Nancy");
string S2("Clancy");
string& rs = s1; //rs指向s1
string *ps = &s1; //ps指向s1
rs = s2; //rs仍然指向s1
//但是s1的值現在
//變為"Clancy"
ps = &s2 //ps現在指向s2:
//但是是s1沒有改變
一般而言,你應該使用指針無論何時你必須考慮到有存在空指向的可能性(在這
種情況下你可以設指針為空)或者你需要能夠在不同的時間指向不同的對象(在這種
情況下你可以改變指針所指的對象).你應該使用引用無論何時你應該知道總是要有
一個對象指向,同時你也應該知道,一旦你指向一個對象,你將再也不能指向任何其它
對象.
有另外一種情況你應該使用引用,那就是當你實現某些操作符時.最普通的例子
是操作符[].遮蓋操作符典型的需要返回能夠作為委派目標的某物:
vector<int> v(10); //創建一個大小為10的整型向量:
//向量是標准C++庫中的模板
//(見Item 35)
v[5] = 10; //委派目標是
//操作符[]的返回值
如果操作符[]返回一個指針,最后一句語句應該這樣寫:
*v[5] = 10;
但是這將使v看起來象一個指針向量,然而它卻不是.因為這個理由,你差不多
總是需要操作符[]返回一個引用.(對于該規則的一個有趣的例外,請看Item 30).
選擇引用的重要條件是當你知道你有某物要指向,當你永遠不需要指向任何其
它的對象,當你需要實現操作符,它的語義要求充分考慮到指針的令人不快的特性.
任何其它情況,堅決使用指針.
Original English:
Item 1: Distinguish between pointers and references. ? Item M1, P1
Pointers and references look different enough (pointers use the "*" and
"->" operators, references use "."), but they seem to do similar things.
Both pointers and references let you refer to other objects indirectly.
How, then, do you decide when to use one and not the other? ? Item M1, P2
First, recognize that there is no such thing as a null reference. A reference
must always refer to some object. As a result, if you have a variable whose
purpose is to refer to another object, but it is possible that there might
not be an object to refer to, you should make the variable a pointer, because
then you can set it to null. On the other hand, if the variable must always
refer to an object, i.e., if your design does not allow for the possibility
that the variable is null, you should probably make the variable a reference.
? Item M1, P3
"But wait," you wonder, "what about underhandedness like this?" ? Item M1, P4
char *pc = 0; // set pointer to null
char& rc = *pc; // make reference refer to
// dereferenced null pointer
Well, this is evil, pure and simple. The results are undefined (compilers can
generate output to do anything they like), and people who write this kind of
code should be shunned until they agree to cease and desist. If you have to
worry about things like this in your software, you're probably best off avoiding
references entirely. Either that or finding a better class of programmers to
work with. We'll henceforth ignore the possibility that a reference can be "null."
? Item M1, P5
Because a reference must refer to an object, C++ requires that references
be initialized: ? Item M1, P6
string& rs; // error! References must
// be initialized
string s("xyzzy");
string& rs = s; // okay, rs refers to s
Pointers are subject to no such restriction: ? Item M1, P7
string *ps; // uninitialized pointer:
// valid but risky
The fact that there is no such thing as a null reference implies that it can
be more efficient to use references than to use pointers. That's because
there's no need to test the validity of a reference before using it: ?
Item M1, P8
void printDouble(const double& rd)
{
cout << rd; // no need to test rd; it
} // must refer to a double
Pointers, on the other hand, should generally be tested against null: ?
Item M1, P9
void printDouble(const double *pd)
{
if (pd) { // check for null pointer
cout << *pd;
}
}
Another important difference between pointers and references is that
pointers may be reassigned to refer to different objects. A reference,
however, always refers to the object with which it is initialized: ?
Item M1, P10
string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs refers to s1
string *ps = &s1; // ps points to s1
rs = s2; // rs still refers to s1,
// but s1's value is now
// "Clancy"
ps = &s2; // ps now points to s2;
// s1 is unchanged
In general, you should use a pointer whenever you need to take into
account the possibility that there's nothing to refer to (in which
case you can set the pointer to null) or whenever you need to be able
to refer to different things at different times (in which case you can
change where the pointer points). You should use a reference whenever
you know there will always be an object to refer to and you also know
that once you're referring to that object, you'll never want to refer
to anything else. ? Item M1, P11
There is one other situation in which you should use a reference, and
that's when you're implementing certain operators. The most common
example is operator[]. This operator typically needs to return something
that can be used as the target of an assignment: ? Item M1, P12
vector<int> v(10); // create an int vector of size 10;
// vector is a template in the
// standard C++ library (see Item 35)
v[5] = 10; // the target of this assignment is
// the return value of operator[]
If operator[] returned a pointer, this last statement would have to be
written this way: ? Item M1, P13
*v[5] = 10;
But this makes it look like v is a vector of pointers, which it's not.
For this reason, you'll almost always want operator[] to return a
reference. (For an interesting exception to this rule, see Item 30.) ?
Item M1, P14
References, then, are the feature of choice when you know you have
something to refer to, when you'll never want to refer to anything
else, and when implementing operators whose syntactic requirements
make the use of pointers undesirable. In all other cases,
stick with pointers.