![](/img/trans.png)
[英]Binding non constant reference to temporary object - An example where it can happen
[英]Constant reference to temporary object
假设有一个类似
void SendToTheWorld(const Foo& f);
我需要在发送之前预处理Foo
对象
X PreprocessFoo(const Foo& f)
{
if (something)
{
// create new object (very expensive).
return Foo();
}
// return original object (cannot be copied)
return f;
}
用法
Foo foo;
SendToTheWorld(PreprocessFoo(foo));
因此, X PreprocessFoo()
函数应该能够返回原始对象或进行复制/修改,而不是返回新对象。 我无法返回const Foo&
因为它可能引用了一个临时对象。 我也不喜欢在堆上创建Foo
。
完美地, X
应该是const Foo&
和Foo
某种联合,可以将其视为const Foo&
。 任何想法如何以更优雅的方式做到这一点?
我当前的解决方案:
Foo PreprocessFoo(const Foo& f)
{
// create new object (very expensive).
return Foo();
}
用法:
Foo foo;
if (something)
{
SendToTheWorld(PreprocessFoo(foo));
}
else
{
SendToTheWorld(foo);
}
我不清楚您的意思是什么,但如果您只是想在返回值中省略Foo
的不必要副本,请减小函数的大小(现在是),然后依靠优化的编译器来处理您的问题问题。
内联函数后,编译器将清除不必要的Foo
副本。
(有兴趣的人注意:NRVO(命名返回值优化) 不能在此处应用,因为不能为可能的返回值的所有实例分配唯一的名称。)
如果不想在堆中创建对象,则应在调用函数之前创建它,然后在该处传递引用。 考虑一下临时对象的性质:该函数在堆栈中创建新对象,然后返回并删除其堆栈框架。 因此,对象应该在那儿或应该在那儿复制。
如果在调用之后不再使用foo
(在调用函数中),则可以使用swap
函数(如果需要,可以为Foo
类专门化std::swap
)来执行此操作:
const Foo& PreprocessFoo(Foo& f)
{
if (something)
{
std::swap(f, Foo());
}
// return original or new object
return f;
}
我能想到的唯一方法是返回Foo对象而不是引用。
Foo PreprocessFoo(const Foo& f)
{
if (something)
{
// create new object
return Foo();
}
// return original object
return f;
}
您当前的解决方案出了什么问题? 由于RVO,可以省略Foo
复制构造函数。 在执行函数SendToTheWorld
时,对临时对象的引用将一直有效。
如果您的Foo对象的生存期不是仅由一段代码来确定,为什么不使用shared_ptr
呢?
void SendToTheWorld( shared_ptr<Foo>& pFoo );
shared_ptr<Foo> preProc( shared_ptr<Foo>& pFoo ) {
if( something ) return new Foo(); // wrapped in a shared pointer
return pFoo;
}
shared_ptr<Foo> pFoo = new Foo();
SendToTheWorld( preProc( pFoo ) );
您的需求是矛盾的:您希望对象是一个自动变量,但您想对它的生命周期发表意见。 无法通过引用返回自动变量。 您可以按价值返回它,但这太昂贵了。 我的想法是:如果复制成本很高,那么与免费存储相比,在自由存储上进行分配的成本可能很小。
您可以使用输出参数,并且大多数时候不复制原始参数:
Foo& preProcess( Foo& f ) {
if( something ) f=Foo(); // hopefully something is special!
return f;
}
Foo localFoo;
SendToTheWorld( preProcess( localFoo ) );
这不是一件容易的事。
我看到了三种解决方法,所有这些都可以降低复印成本。 都需要控制Foo
,也需要控制PreprocessFoo
:
Foo
配备必要的东西,以使它们生效并使复制便宜。 Foo
来实现。 Foo
包装在一些类似于指针的智能对象中,从而使复制便宜。 但是,这将需要动态分配。 如果您不能更改Foo
,那么我看不到办法。
这是另一个想法:如果条件( something
)在编译时已解决,则可以将其设为PreprocessFoo()
的模板参数。 然后,您可以使用TMP分支到具有不同返回类型的两个不同函数。
这是一个草图:
template< bool Cond >
struct to_the_world_sender;
template<>
struct to_the_world_sender<true> {
typedef Foo return_type;
static return_type preprocess(const Foo& foo) {return Foo();}
};
template<>
struct to_the_world_sender<false> {
typedef const Foo& return_type;
static return_type preprocess((const Foo& foo) {return foo;}
};
template< typename Cond >
inline
typename to_the_world_sender<Cond>::return_type PreprocessFoo(const Foo& foo)
{
return to_the_world_sender<Cond>::preprocess((foo);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.