从函数返回对象 [英] Returning object from function
问题描述
现在我真的很困惑如何和使用哪个方法来从函数返回对象。
场景A:
返回的对象存储在一个变量中,不需要修改。其寿命。因此,
const Foo SomeClass :: GetFoo(){
return Foo
}
调用为:
someMethod(){
const Foo& l_Foo = someClassPInstance-> GetFoo();
// ...
}
$ b b
Scneraio B:
返回的对象被存储在一个变量中,该变量在其生命周期中被修改。因此,
void SomeClass :: GetFoo(Foo& a_Foo_ref){
a_Foo_ref = Foo
}
调用为:
someMethod(){
Foo l_Foo;
someClassPInstance-> GetFoo(l_Foo);
// ...
}
我有一个问题:说Foo不能有一个默认的构造函数。那么你在这种情况下如何处理,因为我们不能这样写:
Foo l_Foo
方案C:
Foo SomeClass :: GetFoo(){
return Foo();
}
调用为:
someMethod(){
Foo l_Foo = someClassPInstance-> GetFoo();
// ...
}
我认为这不是推荐的因为它会招致额外的临时性。
你觉得怎么样?
解决方案首先,让我们来看看在这里发生的事情: ://www.drdobbs.com/cpp/184403758rel =nofollow>本出版物作者:Andrei Anexandrescu。再次,它感觉奇怪但有用:
class Foo {...}
Foo GetFoo ){return Foo(); } //返回临时
void UseGetFoo()
{
Foo const& foo = GetFoo();
// ... rock'n'roll ...
foo.StillHere();
}
这条规则说当引用被临时初始化时,扩展,直到引用超出范围。 (此回复引用标准)
(b)返回值优化 - ( wikipedia ) - 在情况下可以省略两个副本local - > return value - > local 。这是一个惊人的规则,因为它允许编译器更改可观察的行为,但有用。
有它。
p> 方案A:您正在返回一个临时项,并将其绑定到引用 - 临时项的生命周期延长到l_Foo的生命周期。
注意,如果 GetFoo
将返回引用而不是临时变量,则这将不起作用。
方案B:工作,除了它强制一个构造 - 构造 - 复制循环(这可能比单结构昂贵得多),以及您提到的需要一个默认构造函数的问题。
我不会使用该模式创建一个对象 - 只能改变现有对象。
strong>场景C:临时表的副本可以由编译器省略(从RVO规则)。不幸的是没有保证 - 但现代编译器确实实现了RVO。
C ++ 0x中的Rvalue引用允许Foo实现一个资源窃取构造函数,它不仅保证压缩副本,而且在其他情况下也很方便。
(我怀疑有一个编译器实现了右值引用而不是RVO,但是有些情况下RVO无法启动。)
这样的问题需要提到智能指针,例如 shared_ptr
和 unique_ptr
(后者是一个安全 auto_ptr
)。他们也在 C ++ 0x 中。它们为创建对象的函数提供了一种备用模式。
I am really confused now on how and which method to use to return object from a function. I want some feedback on the solutions for the given requirements.
Scenario A:
The returned object is to be stored in a variable which need not be modified during its lifetime. Thus,
const Foo SomeClass::GetFoo() {
return Foo();
}
invoked as:
someMethod() {
const Foo& l_Foo = someClassPInstance->GetFoo();
//...
}
Scneraio B:
The returned object is to be stored in a variable which will be modified during its lifetime. Thus,
void SomeClass::GetFoo(Foo& a_Foo_ref) {
a_Foo_ref = Foo();
}
invoked as:
someMethod() {
Foo l_Foo;
someClassPInstance->GetFoo(l_Foo);
//...
}
I have one question here: Lets say that Foo cannot have a default constructor. Then how would you deal with that in this situation, since we cant write this anymore:
Foo l_Foo
Scenario C:
Foo SomeClass::GetFoo() {
return Foo();
}
invoked as:
someMethod() {
Foo l_Foo = someClassPInstance->GetFoo();
//...
}
I think this is not the recommended approach since it would incur constructing extra temporaries.
What do you think ? Also, do you recommend a better way to handle this instead ?
解决方案 First, let's look into the things that come into play here:
(a) Extending lifetime of a temporary when it's used to initialize a reference - I learnt about it in this publication by Andrei Anexandrescu. Again, it feels weird but useful:
class Foo { ... }
Foo GetFoo() { return Foo(); } // returning temporary
void UseGetFoo()
{
Foo const & foo = GetFoo();
// ... rock'n'roll ...
foo.StillHere();
}
The rule says that when a reference is initialized with a temporary, the temporary's lifetime is extended until the reference goes out of scope. (this reply quotes the canon)
(b) Return Value Optimization - (wikipedia) - the two copies local --> return value --> local may be omitted under circumstances. That's a surprising rule, as it allows the compiler to change the observable behavior, but useful.
There you have it. C++ - weird but useful.
So looking at your scenarios
Scenario A: you are returning a temporary, and bind it to a reference - the temporary's lifetime is extended to the lifetime of l_Foo.
Note that this wouldn't work if GetFoo
would return a reference rather than a temporary.
Scenario B: Works, except that it forces a Construct-Construct-Copy-Cycle (which may be much more expensive than single construct), and the problem you mention about requiring a default constructor.
I wouldn't use that pattern to create a object - only to mutate an existing one.
Scenario C: The copies of temporaries can be omitted by the compiler (as of RVO rule). There is unfortunately no guarantee - but modern compilers do implement RVO.
Rvalue references in C++ 0x allows Foo to implement a resource pilfering constructor that not only guarantees supression of the copies, but comes in handy in other scenarios as well.
(I doubt that there's a compiler that implements rvalue references but not RVO. However there are scenarios where RVO can't kick in.)
A question like this requires mentioning smart pointers, such as shared_ptr
and unique_ptr
(the latter being a "safe" auto_ptr
). They are also in C++ 0x. They provide an alternate pattern for functions creating objects.
这篇关于从函数返回对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!