当前位置:  开发笔记 > 编程语言 > 正文

是否可能从参考中产生分段错误?

如何解决《是否可能从参考中产生分段错误?》经验,为你挑选了3个好方法。

假设以下代码:

Foo & foo = getFoo();
foo.attr; // 100% safe access?

如果foo是一个指针,我会检查它是否NULL,但因为它是一个引用,这样的检查是不必要的.我想知道的是,是否有可能弄乱对象的引用,以致它将使访问其属性不安全.

我尝试了一些例子,比如试图转换NULLFoo对象,但是我遇到了编译错误.我只是想确保上面的代码总是安全的,并且C++我不应该知道内在的黑魔法.

根据Benjamin的回答,我可以制作一个示例代码,我从引用中得到分段错误,因此它回答了我的问题.我会粘贴我的代码,万一有人对未来感兴趣:

#include 
using 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的回答中所提到的,有效的引用在完全合法的代码中可能变得无效(尽管不是空).但是你没办法检查这个.您只需要知道它可能发生在什么情况下,然后停止使用该引用.



1> Benjamin Lin..:

是的,这是可能的.

Foo& Fr = *(Foo*)nullptr;

从技术上讲,这已经是取消引用该指针的未定义行为.但它很可能不会导致任何可观察到的错误.这可能会:

Fr.attr = 10;

但是,正如Jonathan Wakely在评论中指出的那样,你没有理由检查这样的案例.如果函数返回无效引用,则该函数被破坏,需要修复.假设引用有效,您的使用代码不会被破坏.但是,正如David Schwartz的回答中所提到的,有效的引用在完全合法的代码中可能变得无效(尽管不是空).但是你没办法检查这个.您只需要知道它可能发生在什么情况下,然后停止使用该引用.



2> David Schwar..:

在引用该引用时,引用必须引用有效对象.这是一个C++标准要求,违反它的任何代码都是UB,可以做任何事情.

但是,在参考坐下之后销毁参考引用的对象是完全合法的.此时,访问引用是非法的.例如:

std::vector j;
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::vector j;
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::vector j;
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


注意OP,在执行`k ++`之前无法检测到`k`无效."k"的有效性是你必须通过程序的逻辑来确保达到这一点的.

3> Fantastic Mr..:

可以引用不良内存.所以答案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()写错了,需要修复.没有办法或理由检查这一点.如果一个函数返回一个错误的引用,那么你唯一可以(而且应该)做的就是修复有问题的函数.

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有