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