假设以下代码:
Foo & foo = getFoo(); foo.attr; // 100% safe access?
如果foo
是一个指针,我会检查它是否NULL
,但因为它是一个引用,这样的检查是不必要的.我想知道的是,是否有可能弄乱对象的引用,以致它将使访问其属性不安全.
我尝试了一些例子,比如试图转换NULL
为Foo
对象,但是我遇到了编译错误.我只是想确保上面的代码总是安全的,并且C++
我不应该知道内在的黑魔法.
根据Benjamin的回答,我可以制作一个示例代码,我从引用中得到分段错误,因此它回答了我的问题.我会粘贴我的代码,万一有人对未来感兴趣:
#includeusing namespace std; class B { public: int x; B() {x = 5;} }; class A { public: void f() { b = *(B*)NULL; } B & getB() { return b; } B b; }; int main() { A a; a.f(); cout << a.getB().x << endl; return 0; }
Benjamin Lin.. 28
是的,这是可能的.
Foo& Fr = *(Foo*)nullptr;
从技术上讲,这已经是取消引用该指针的未定义行为.但它很可能不会导致任何可观察到的错误.这可能会:
Fr.attr = 10;
但是,正如Jonathan Wakely在评论中指出的那样,你没有理由检查这样的案例.如果函数返回无效引用,则该函数被破坏,需要修复.假设引用有效,您的使用代码不会被破坏.但是,正如David Schwartz的回答中所提到的,有效的引用在完全合法的代码中可能变得无效(尽管不是空).但是你没办法检查这个.您只需要知道它可能发生在什么情况下,然后停止使用该引用.
是的,这是可能的.
Foo& Fr = *(Foo*)nullptr;
从技术上讲,这已经是取消引用该指针的未定义行为.但它很可能不会导致任何可观察到的错误.这可能会:
Fr.attr = 10;
但是,正如Jonathan Wakely在评论中指出的那样,你没有理由检查这样的案例.如果函数返回无效引用,则该函数被破坏,需要修复.假设引用有效,您的使用代码不会被破坏.但是,正如David Schwartz的回答中所提到的,有效的引用在完全合法的代码中可能变得无效(尽管不是空).但是你没办法检查这个.您只需要知道它可能发生在什么情况下,然后停止使用该引用.
在引用该引用时,引用必须引用有效对象.这是一个C++标准要求,违反它的任何代码都是UB,可以做任何事情.
但是,在参考坐下之后销毁参考引用的对象是完全合法的.此时,访问引用是非法的.例如:
std::vectorj; j.push_back(3); int& k = j.front(); // legal, object exists now j.clear(); // legal, object may be destroyed while reference exists k++; // illegal, destruction of object invalidates reference
这意味着返回引用的函数必须始终返回在返回时有效的引用.这就是为什么调用front
一个空向量是UB - 一个引用必须在它就位时有效.但是,通常会有条件随后使该引用无效,如果您打算尝试存储引用并稍后访问它,则需要了解这些条件是什么.
通常,您应该假设存储返回的引用并稍后访问它是不安全的,除非您知道引用将保持有效.例如,std::vector
仔细解释在什么条件下对容器的引用可以无效,并且包括随后的调用push_back
.所以这打破了:
std::vectorj; j.push_back(3); int &first = j.front(); j.push_back(4); int &second = j.back(); if (first == second) // illegal, references into container are invalidated by push_back
但这很好:
std::vectorj; j.push_back(3); j.push_back(4); int &first = j.front(); int &second = j.back(); if (first == second) // legal, references into container stay valid
可以引用不良内存.所以答案foo.attr; // 100% safe access?
是否定的.请考虑以下示例:
int &something() { int i = 5, &j = i; return j; // Return reference to local variable. This is destroyed at end of scope. } int main() { int &k = something(); // Equivalent to getFoo() std::cout << k << endl; // Using this reference is undefined behavior. return 0; }
实例.
引用k没有指向合法的内存.但这仍然会编译.然而,在程序员没有犯错误的情况下,情况并非如此.在这种情况下,函数something()
写错了,需要修复.没有办法或理由检查这一点.如果一个函数返回一个错误的引用,那么你唯一可以(而且应该)做的就是修复有问题的函数.