C++核心準(zhǔn)則ES.65:不要解引用無效指針

ES.65: Don't dereference an invalid pointer
ES.65:不要解引用無效指針
Reason(原因)
Dereferencing an invalid pointer, such as?nullptr, is undefined behavior, typically leading to immediate crashes, wrong results, or memory corruption.
解引用例如null等無效指針,是無定義的行為,通常會(huì)立即導(dǎo)致程序崩潰,錯(cuò)誤的結(jié)果,或者內(nèi)存破壞。
Note(注意)
This rule is an obvious and well-known language rule, but can be hard to follow. It takes good coding style, library support, and static analysis to eliminate violations without major overhead. This is a major part of the discussion of?C++'s model for type- and resource-safety.
本規(guī)則顯而易見而且眾所周知,但卻很難遵守。它會(huì)帶來好的代碼風(fēng)格,更充分的庫支持,不需要很大代價(jià)但可以排除違反的靜態(tài)解析。這是關(guān)于C++類型和資源安全模型的論述的重要組成部分。
See also:(參見)
Use?RAII?to avoid lifetime problems.
使用RAII避免生命周期問題。
Use?unique_ptr?to avoid lifetime problems.
使用unique_ptr避免生命周期問題
Use?shared_ptr?to avoid lifetime problems.
使用shared_ptr避免生命周期問題
Use?references?when?nullptr?isn't a possibility.
如果不可能出現(xiàn)空指針,使用引用
Use?not_null?to catch unexpected?nullptr?early.
使用not_null盡早捕獲意外的空指針。
Use the?bounds profile?to avoid range errors.
使用邊界規(guī)則群組避免范圍錯(cuò)誤。
Example(示例)
void f()
{
int x = 0;
int* p = &x;
if (condition()) {
int y = 0;
p = &y;
} // invalidates p
*p = 42; // BAD, p might be invalid if the branch was taken
}
To resolve the problem, either extend the lifetime of the object the pointer is intended to refer to, or shorten the lifetime of the pointer (move the dereference to before the pointed-to object's lifetime ends).
為了解決這個(gè)問題,要么擴(kuò)展對(duì)象指針意圖指向的對(duì)象的生命周期,要么縮短指針的生命周期(將解引用操作移到所指向?qū)ο蟮纳芷诮Y(jié)束之前。)
void f1()
{
int x = 0;
int* p = &x;
int y = 0;
if (condition()) {
p = &y;
}
*p = 42; // OK, p points to x or y and both are still in scope
}
Unfortunately, most invalid pointer problems are harder to spot and harder to fix.
不幸的是,大多數(shù)無效指針問題難于發(fā)現(xiàn),也難于修改。
Example(示例)
void f(int* p)
{
int x = *p; // BAD: how do we know that p is valid?
}
There is a huge amount of such code. Most works -- after lots of testing -- but in isolation it is impossible to tell whether?p?could be the?nullptr. Consequently, this is also a major source of errors. There are many approaches to dealing with this potential problem:
這樣的代碼大量存在。在經(jīng)歷了大量測(cè)試之后,大部分情況下可以動(dòng)作,但是如果只看局部很難判斷一個(gè)指針有沒有可能為空。因此,空指針也是錯(cuò)誤的主要來源之一。存在很多方法可以處理這個(gè)潛在問題:
void f1(int* p) // deal with nullptr
{
if (!p) {
// deal with nullptr (allocate, return, throw, make p point to something, whatever
}
int x = *p;
}
There are two potential problems with testing for?nullptr:
檢查指針是否為空會(huì)有兩個(gè)潛在問題:
it is not always obvious what to do what to do if we find?nullptr
在發(fā)現(xiàn)了空指針時(shí)應(yīng)該做什么并不總是很明確。
the test can be redundant and/or relatively expensive
檢查可能是多余的而且/或者代價(jià)相當(dāng)高。
it is not obvious if the test is to protect against a violation or part of the required logic.
很難判斷這個(gè)檢查只是為了防止違反還是必要邏輯的一部分。
void f2(int* p) // state that p is not supposed to be nullptr
{
assert(p);
int x = *p;
}
This would carry a cost only when the assertion checking was enabled and would give a compiler/analyzer useful information. This would work even better if/when C++ gets direct support for contracts:
這種做法只在斷言檢查有效時(shí)需要付出一定的代價(jià),同時(shí)可以為編譯器/解析器提供有用信息。如果C++得到協(xié)議(contracts)的直接支持的話,效果會(huì)更好:
void f3(int* p) // state that p is not supposed to be nullptr
[[expects: p]]
{
int x = *p;
}
Alternatively, we could use?gsl::not_null?to ensure that?p?is not the?nullptr.
另外,我們可以使用gsl::not_null來保證p不是空指針。
void f(not_null p)
{
int x = *p;
}
These remedies take care of?nullptr?only. Remember that there are other ways of getting an invalid pointer.
這個(gè)改進(jìn)只處理空指針。別忘了還有其他形式的無效指針。
Example(示例)
void f(int* p) // old code, doesn't use owner
{
delete p;
}
void g() // old code: uses naked new
{
auto q = new int{7};
f(q);
int x = *q; // BAD: dereferences invalid pointer
}Example(示例)
void f()
{
vector v(10);
int* p = &v[5];
v.push_back(99); // could reallocate v's elements
int x = *p; // BAD: dereferences potentially invalid pointer
} Enforcement(實(shí)施建議)
This rule is part of the?lifetime safety profile
本規(guī)則是生命周期規(guī)則群組的一部分
Flag a dereference of a pointer that points to an object that has gone out of scope
如果指針指向的對(duì)象已經(jīng)處于生命周期之外,標(biāo)記它的解引用操作。
Flag a dereference of a pointer that may have been invalidated by assigning a?nullptr
如果指針由于被設(shè)為空指針而無效時(shí),標(biāo)記它的解引用操作。
Flag a dereference of a pointer that may have been invalidated by a?delete
如果由于指針指向的對(duì)象被銷毀而無效時(shí),標(biāo)記它的解引用操作。
Flag a dereference to a pointer to a container element that may have been invalidated by dereference
如果指針指向的容器元素由于解引用而無效時(shí),標(biāo)記它的解引用操作。
原文鏈接
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es65-dont-dereference-an-invalid-pointer
覺得本文有幫助?請(qǐng)分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>
