从函数返回对象

bra*_*ter 19 c++ memory return-value pass-by-reference

我现在真的很困惑如何以及使用哪种方法从函数返回对象.我想要针对给定要求的解决方案提供一些反馈.

场景A:返回的对象将存储在一个变量中,该变量在其生命周期内无需修改.从而,

const Foo SomeClass::GetFoo() {
 return Foo(); 
}
Run Code Online (Sandbox Code Playgroud)

调用为:

someMethod() {
 const Foo& l_Foo = someClassPInstance->GetFoo();
//...
}
Run Code Online (Sandbox Code Playgroud)

Scneraio B:返回的对象将存储在一个变量中,该变量将在其生命周期内被修改.从而,

void SomeClass::GetFoo(Foo& a_Foo_ref) {
     a_Foo_ref = Foo(); 
    }
Run Code Online (Sandbox Code Playgroud)

调用为:

someMethod() {
 Foo l_Foo;
 someClassPInstance->GetFoo(l_Foo);
//...
}
Run Code Online (Sandbox Code Playgroud)

我在这里有一个问题:让我们说Foo不能有默认的构造函数.那么在这种情况下你会怎么处理呢,因为我们不能再写这个了:

Foo l_Foo
Run Code Online (Sandbox Code Playgroud)

场景C:

Foo SomeClass::GetFoo() {
 return Foo(); 
}
Run Code Online (Sandbox Code Playgroud)

调用为:

someMethod() {
 Foo l_Foo = someClassPInstance->GetFoo();
//...
}
Run Code Online (Sandbox Code Playgroud)

我认为这不是推荐的方法,因为它会导致构建额外的临时工.

你怎么看 ?另外,您是否建议使用更好的方法来处理此问题?

pet*_*hen 16

首先,让我们来看看这里发挥作用的事情:

(a)延长临时用于初始化参考的寿命 - 我在本出版物中由Andrei Anexandrescu 了解到它.再次,它感觉很奇怪,但很有用:

class Foo { ... }

Foo GetFoo() { return Foo(); }  // returning temporary

void UseGetFoo()
{
   Foo const & foo = GetFoo();
   // ... rock'n'roll ...
   foo.StillHere();
}
Run Code Online (Sandbox Code Playgroud)

规则说,当使用临时初始化引用时,临时的生命周期将延长,直到引用超出范围.(这个回复引用了佳能)

(b)返回值优化 - (维基百科) - 本地的两个副本 - >返回值 - >本地可能在某些情况下被省略.这是一个令人惊讶的规则,因为它允许编译器更改可观察的行为,但很有用.

你有它.C++ - 奇怪但有用.


所以看看你的场景

场景A:您返回一个临时的,并将其绑定到引用 - 临时的生命周期延长到l_Foo的生命周期.

请注意,如果GetFoo返回引用而不是临时引用,则无效.

场景B:工作,除了它强制构造 - 构造 - 复制周期(可能比单个构造更昂贵),以及您提到的关于需要默认构造函数的问题.

我不会使用该模式来创建对象 - 仅用于改变现有对象.

场景C:编译器可以省略临时副本(从RVO规则开始).遗憾的是没有保证 - 但现代编译器确实实现了RVO.

C++ 0x中的Rvalue引用允许Foo实现资源窃取构造函数,不仅可以保证副本的抑制,而且在其他场景中也可以派上用场.

(我怀疑有一个编译器实现了右值引用而不是RVO.但是有些情况下RVO无法启动.)


像这样的问题需要提到智能指针,例如shared_ptrunique_ptr(后者是"安全的" auto_ptr).它们也在C++ 0x中.它们为创建对象的函数提供了另一种模式.