2011-04-14 108 views
10

Possible Duplicate:
warning: returning reference to temporaryC++返回参考临时

我正在错误下面的第二行“返回参考临时”。

class Object : public std::map <ExString, AnotherObject> const { 
public: 
const AnotherObject& Find (const ExString& string) const { 
    Object::const_iterator it = find (string); 
    if (it == this->end()) { return AnotherObject() }; 
    return (it->second); 
} 
} 

我的类实现了std :: map。

我是C++新手,所以我猜它只是一个语法错误。任何帮助?

+1

代码所在的函数签名是什么?或者那个代码的上下文是什么? – Xeo 2011-04-14 17:29:38

+0

我填写了一些细节 – dcinadr 2011-04-14 17:33:36

回答

3

您正在堆栈AnotherObject()上创建一个临时值,并在其被破坏之前将其返回。你的函数的调用者会得到垃圾,所以它是被禁止的。

也许你想分配它在堆上,并返回一个指针呢?

return new AnotherObject(); 

另外,声明你的函数返回一个“拷贝”到你的对象,而不是一个参考像我假设你现在正在返回:

AnotherObject f() 
{ 
    return AnotherObject(); // return value optimization will kick in anyway! 
} 
+0

或者你可能想要按价值归还它。这通常是这种情况(但它显然取决于'AnotherObject'的语义)。 – 2011-04-14 17:33:06

+0

自从我触摸C++之后,我一直很好,但我仍然猜对了参考部分! – Blindy 2011-04-14 17:33:37

+0

返回新的AnotherObject()不起作用。我得到一个错误:类型为'AnotherObject *'的表达式类型为'const AnotherObject'的invalide初始化引用 – dcinadr 2011-04-14 18:21:17

15

如果你的函数看起来像这样:

AnotherObject& getAnotherObject() 
{ 

    . . . 

    Object::const_iterator it = find ("lang"); 
    if (it == this->end()) { return AnotherObject() }; 

    . . . 

} 

的问题是AnotherObject()你返回将尽快销毁函数退出,所以调用者的功能将有一个假的对象的引用。

如果你的函数由返回值但是:

AnotherObject getAnotherObject() 

那么原来被销毁前一个副本将被制成,你会没事的。

+0

很棒的回答。只是补充一点,如果你使用'new',你应该注意这个函数的泄漏。你应该把它们包装在'auto_ptr'或'shared_ptr'中以防止你自己做不小心的泄漏。 – lxcid 2011-04-14 17:44:22

6

return AnotherObject();创建一个在函数退出前销毁的对象 - 临时表达式在包含它们的表达式末尾销毁[*],并且表达式AnotherObject()创建一个临时表达式。

由于该函数通过引用返回,这意味着调用者甚至有机会看到该引用,它不再引用有效的对象。

如果该函数是按值返回的话,那将是可以的,因为临时文件将被复制[**]。

[*]有几种情况没有,但他们不帮你在这里。

[**]其实有一个优化称为“复制构造函数省略”,这意味着临时不需要创建,复制和销毁。相反,在某些条件下,编译器只允许创建副本的目标,就像创建临时目录一样,而不用担心临时存在。

1

函数必须声明为返回引用,并且引用必须引用在函数退出后将继续存在的对象。您的临时“AnotherObject()”在返回后立即被破坏,因此显然不起作用。如果您无法更改方法签名,则可能需要抛出异常而不是返回错误值。

1

您应该将函数的返回类型从“AnotherObject &”更改为“AnotherObject”并按值返回该对象。否则它就像Blindy描述的一样

0

对AnotherObject的构造函数的调用会在堆栈中创建一个新实例,当该方法返回时该实例立即被销毁。

如果查找失败,创建并返回新对象很可能不是一个好主意。调用代码将无法判断返回的对象是否是先前存在于数据结构中的对象。

如果您确实想这样做,那么您应该将新对象添加到数据结构中,然后返回指向新对象的迭代器在数据结构中。

事情是这样的:

if (it == this->end()) { 
    it = this->insert(pair<ExString, AnotherObject>(string, AnotherObject())); 
    return it->second; 
}  
+0

你能举个例子吗? – dcinadr 2011-04-14 18:24:09

+0

@dcinadr添加了代码示例。 – ravenspoint 2011-04-14 18:39:31

0

您应该参考不能回到其在该行的最后摧毁了一个临时的,也不是一个地方一个参考它在功能的结束时被销毁。

如果您想保留当前签名,您必须添加一个静态常量实例,您可以将其作为默认值返回。

#include <iostream> 

template <class T> 
class X 
{ 
    T value; 
    static const T default_instance; 
public: 
    X(const T& t): value(t) {} 
    const T& get(bool b) const 
    { 
     return b ? value : default_instance; 
    } 
}; 

template <class T> 
const T X<T>::default_instance = T(); 

int main() 
{ 
    X<int> x(10); 
    std::cout << x.get(true) << ' ' << x.get(false) << '\n'; 
} 

你也可以返回值或返回一个指针,在这种情况下你可以返回NULL。

0

我个人认为这有点破解,但只要你真的坚持返回引用的常量,你应该能够返回一个静态构造的AnotherObject实例,它的唯一“存在d” etre“是您的函数的”未找到“返回值。例如,将其设置为类Object的静态常量私有成员,只要AnotherObject的默认构造实例不是要包含在Object实例中的有效值,就应该可以。