C++ C++;当我通过引用传递一个对象而它超出范围时?

C++ C++;当我通过引用传递一个对象而它超出范围时?,c++,C++,我认为最好用我刚刚写的一段小代码来回答这个问题: #include <iostream> using namespace std; class BasicClass { public: BasicClass() { } void print() { cout << "I'm printing" << endl; } }; class FriendlyClass { public: F

我认为最好用我刚刚写的一段小代码来回答这个问题:

#include <iostream>

using namespace std;

class BasicClass
{
public:
    BasicClass()
    {
    }
    void print()
    {
        cout << "I'm printing" << endl;
    }
};

class FriendlyClass
{
public:
    FriendlyClass(BasicClass& myFriend) :
        _myFriend(myFriend)
    {
    }
    void printFriend()
    {
        cout << "Printing my friend: ";
        _myFriend.print();
    }
private:
    BasicClass& _myFriend;
};

int main(int argv, char** argc)
{
    FriendlyClass* fc;
    {
        BasicClass bc;
        fc = new FriendlyClass(bc);
        fc->printFriend();
    }
    fc->printFriend();
    delete fc;
    return 0;
}

然而,这不是我所期望的行为。我原以为第二次调用
fc->printFriend()
时会出现某种故障。我对引用传递/存储工作原理的理解是否不正确,或者这只是碰巧在小范围内工作,并且可能在更复杂的应用程序中崩溃?

未定义的行为。根据定义,您不能假设代码运行时会发生什么。编译器可能还没有清除
bc
所在的内存,但您不能指望它


事实上,我在一次工作中修复了一个程序中的相同错误。使用英特尔编译器时,超出范围的变量尚未“清理”,因此内存仍然“有效”(但行为未定义)。然而,微软的编译器更积极地清理了它,这个错误是显而易见的。

当您存储对已结束其生命周期的对象的引用时,访问它是未定义的行为。因此,任何事情都可能发生,它可能工作,它可能失败,它可能崩溃,正如我想说的那样,它可以点比萨饼。

它的工作原理与指针完全相同:使用指向不再存在的对象的某物(指针/引用)是未定义的行为。它可能看起来有效,但随时可能损坏

警告:下面是一个快速的解释,说明为什么这种方法调用似乎可以在几种情况下工作,只是为了提供信息;在编写实际代码时,您应该只依赖标准所说的内容

至于您所观察到的行为:在大多数(所有?)编译器上,方法调用是作为函数调用实现的,带有一个隐藏的
这个
参数,该参数引用方法将要操作的类的实例。但是在您的例子中,根本没有使用
this
指针(函数中的代码没有引用任何字段,并且没有虚拟分派),因此(现在无效)
this
指针没有使用,调用成功

在其他情况下,即使它引用的是范围外的对象,它也可能会工作,因为它的内存尚未被重用(尽管析构函数已经运行,因此该方法可能会发现该对象处于不一致的状态)


同样,您不应该依赖这些信息,它只是让您知道为什么调用仍然有效。

您有一个悬空引用,这会导致未定义的行为

  • 看这里:

  • 它几乎可以工作,因为您没有虚拟函数,也不访问BasicClass的字段:您调用的所有方法都有静态绑定,并且从不使用“this”, 因此,您永远不会真正访问“未分配内存”


  • 当我们齐声喊“未定义的行为!”时,你不喜欢吗?8v)“我以为第二天会有某种失败”。只需打印()虚拟或存储你正在打印的文本作为STD::String成员变量,你就会得到失败。C++一般不希望引用作为数据成员。您可能来自Java背景。C++引用与java引用无关。如果您想要Java引用之类的东西,请使用
    std::shared_ptr
    并在堆上创建对象。我已经将代码中的
    unique_ptr
    shared_ptr
    弱_ptr
    完全转换为
    unique_ptr
    ,我很享受内存泄漏的不足:)@R.MartinhoFernandes:这将是符合标准的行为@R.马丁尼奥·费尔南德斯:是的,但不一定。你不能依赖它,因为它的行为是不明确的。不过,从来没有任何一种不明确的行为导致我吃比萨饼。我只是想记录在案。
    $ g++ test.cc -o test
    $ ./test
    Printing my friend: I'm printing
    Printing my friend: I'm printing