2010-01-13 50 views
0

即使函数返回的值是该函数的局部变量,是否可以返回const引用?我知道当函数返回时,局部变量不再有效 - 但是如果函数被内联并且返回的值仅在调用者范围内使用,该怎么办?那么函数的本地应该被包含在调用者堆栈中,不是吗?C++返回本地变量的const引用

回答

8

不要指望它。即使这对一个编译器有效,它也不是标准支持的行为,并且很可能在其他编译器上打破。

0

当被调用者超出范围时,该值超出范围。所以不,它消失了。

但是,如果你想有一个相当丑陋的解决方案(和红旗警告你,你的设计可能需要重构),你可以做这样的事情:

const MyObj& GetObj() 
{ 
    static const MyObj obj_; 
    return obj_; 
} 

...但这种解决方案是否充满危险,特别是如果对象是可修改的,或者在多线程环境中做一些不平凡的事情。

+0

对于不可修改的对象,这实际上并不是一个不好的解决方案。 – 2010-01-13 15:43:05

+0

如果它们是不可变的,它们可以在外部范围内声明,并且不需要实际返回它们。 – 2010-01-13 15:45:38

4

inline保证 - 这是一个建议。即使您使用技巧强制内联,您也永远无法确定结果,特别是如果您想保持便携性。因此,不要做到这一点。

0

inline关键字不保证该函数是真正内联的。不要这样做。

5

不,它不好。局部变量在堆栈中声明,堆栈在方法调用之间不断变化。而且,超出范围的对象也会被销毁。总是返回一个局部变量的副本。

考虑以下代码:

#include <iostream> 
using namespace std; 

class MyClass 
{ 
public: 
    MyClass() { cout << "ctor" << endl; } 
    ~MyClass() { cout << "dtor" << endl; } 
    MyClass(const MyClass& r) { cout << "copy" << endl; } 
}; 

const MyClass& Test() 
{ 
    MyClass m; 
    return m; 
} 

int main() 
{ 
    cout << "before Test" << endl; 
    MyClass m = Test(); 
    cout << "after Test" << endl; 
} 

这将打印出:

before Test 
ctor 
dtor 
copy 
after Test 
dtor 

你要复制的对象已经要求其析构函数,并且可以处于无效状态。

1

这样做会调用未定义的行为。

  • 有没有办法强制编译器内联函数。 inline只是一个建议 - 也是如此__forceinline
  • 即使你可以保证该函数将被内联,所讨论变量的析构函数仍然会被执行,留给你一个对死对象的引用。
  • 而大的 - C++的堆栈概念是由作用域划分的 - 而不是按功能划分的。

#include <iostream> 
int main() 
{ 
    { 
    int a = 5; 
    std::cout << std::hex << "0x" << &a << std::endl; 
    } 
    { 
    int b = 10; 
    std::cout << std::hex << "0x" << &b << std::endl; 
    } 
} 

我的编译器放 'A' 和 'B' 在不同的内存地址。 除开启优化之外。你可能会认为这是一个优化重用你的对象以前占用的内存。

你在这里试图解决一个问题吗?如果这是您的担忧,还有其他方法可以减少创建的临时对象的数量。

+0

你还记得你究竟在哪里学习C++堆栈是由范围分隔的吗? – 2010-01-13 15:58:48

+0

不可以。但是析构函数调用发生在范围边界上,而不是函数边界,所以看起来很明显。 – 2010-01-13 16:00:24

+0

不是。析构函数在范围边界上被调用,但这并不意味着堆栈在该边界上被卷起或展开。我只是看了一个简单的应用程序,它有两个嵌套在另一个范围内的应用程序,并且看到栈指针没有任何反应。试过版本和调试版本。那么,我想正确的答案是 - 它是编译器特定的。 – 2010-01-13 16:05:14

1

正如其他人所指出的,这是危险的。如果您的编译器支持NRVO(命名返回值优化),并且您的函数使用并返回您本来希望以ref以相当简单的方式返回的局部变量,那也没有必要。

NRVO允许编译器在特定条件下避免复制构造 - 通常是避免按值返回对象的主要原因。 VC++ 8支持这个(在以前的修订版上是一个增量),并且它在经常使用的代码中有相当多的性能差异。