返回引用 - 为什么我的代码正常工作?它不应该

时间:2013-12-24 20:39:04

标签: c++ visual-studio-2010 reference

我对C ++中的引用有一些疑问。

Test & returnref(){
    Test obj(9,9);
    cout << "in function: " << &obj << endl;
    return obj;
} // *

int main(){

    Test & asdf = returnref();
    Test asdf2 = returnref();
    cout << "in main asdf: " << &asdf;
    cout << "in main asdf2: " << &asdf2;

    cin.get();
    return 0;

}

结果:

in function: 0033F854
in function: 0033F854
in main asdf: 0033F854
in main asdf2: 0033F938

是对的吗? 在我看来,obj正在第5行被删除(*) - 因为它在这个函数范围内是活的。 为什么它的工作原理?它只是Visual Studio吗?或者我错了?

3 个答案:

答案 0 :(得分:3)

您正在函数的stack上分配一个对象,当函数返回时,

使用的对象被销毁。使用new动态分配它(然后删除当然),而不是

做你需要的任何事情。

答案 1 :(得分:1)

使用对函数返回的局部变量的引用具有未定义的行为。但请注意,ub并不意味着“它会崩溃”,意思是“我不知道会发生什么”。

在您的情况下,您的调用不会重复使用该堆栈所使用的内存,因此您的局部变量仍然存在。

答案 2 :(得分:1)

您的选择是按值返回或返回基于堆的对象的引用/指针。

按值返回

将您的功能签名更改为此

Test returnval()

将复制obj。请注意,打印出的指针对于类中的对象和外部对象可能仍具有相同的值,因为编译器可能已执行return value optimisation

如果Test类不管理动态分配的资源,那么您可以依赖编译器将注入的自动创建的复制构造函数。如果Test已动态分配数据,那么您必须编写自己的数据。请参阅What is the Rule of Three?

将指针(或引用)返回到基于堆的对象

您可以使用new将其更改为基于堆的对象,然后返回指针:

Test* returnptr(){
    Test* obj = new Test(9,9);
    cout << "in function: " << obj << endl;
    return obj;
}

或者更好的是,像shared_ptr这样的智能指针可以为您管理删除:

shared_ptr<Test> returnptr() {
    // Wrapping the pointer in a shared_ptr will ensure it gets cleaned 
    // up automatically when the last reference to it (usage of it) 
    // goes out of scope. 
    shared_ptr<Test> obj(new Test(9,9));    
    cout << "in function: " << obj.get() << endl;
    return obj;
}

最后的注释

正如我的回答中的一位评论者所指出的,在C ++ 11中,您还可以通过为Test提供移动构造函数并使用{{}来控制函数中临时对象的返回方式。必要时1}}这是一个相当多的主题,但您可以通过以下链接阅读更多相关信息: