假设有一个像
这样的函数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);
}
答案 0 :(得分:2)
我不是100%清楚你的意思,但是如果你只是想在返回值中省略不必要的Foo
副本,那么让你的函数变小(现在,它是)并依赖于优化编译器以处理您的问题。
一旦内联函数,编译器将忽略Foo
。
(注意感兴趣:NRVO(命名返回值优化)不能在此处应用,因为不能为可能的返回值的所有实例分配唯一名称。)
答案 1 :(得分:1)
如果你不想在堆中创建对象,那么你应该在调用函数之前创建它并在那里传递一个引用。想想临时性的本质:函数在堆栈中创建新对象,然后返回,删除其堆栈帧。所以对象应该在那里,或者应该在那里复制。
答案 2 :(得分:1)
如果调用后foo
(在调用函数中)没有再次使用,您可以使用swap
函数(专门为std::swap
进行类{{1}如有必要):
Foo
答案 3 :(得分:0)
我能想到的唯一方法是返回一个Foo对象而不是一个引用。
答案 4 :(得分:0)
Foo PreprocessFoo(const Foo& f)
{
if (something)
{
// create new object
return Foo();
}
// return original object
return f;
}
答案 5 :(得分:0)
您当前的解决方案有什么问题?由于RVO,Foo
的复制构造函数可以省略。在执行函数SendToTheWorld
时,对临时对象的引用将始终有效。
答案 6 :(得分:0)
如果您的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 ) );
答案 7 :(得分:0)
您的要求存在冲突:您希望对象成为自动变量,但您希望对其生命周期发表意见。通过引用返回自动变量是不可能的。你可以按价值归还,但这太贵了。我的想法是:如果复制成本如此之高,那么分配给免费商店的成本可能比较小。
您可以使用输出参数,大部分时间不能复制原始参数:
Foo& preProcess( Foo& f ) {
if( something ) f=Foo(); // hopefully something is special!
return f;
}
Foo localFoo;
SendToTheWorld( preProcess( localFoo ) );
答案 8 :(得分:0)
这不是一件容易的事。
我看到了解决这个问题的三种方法,所有这些都归结为使复制更便宜。所有这些都需要控制Foo
,还需要控制PreprocessFoo
:
Foo
装备必要的东西,让它们启动并使复制变得便宜。 Foo
以实现该目标。 Foo
,使复制变得便宜。但是,这需要动态分配。 如果您无法更改Foo
,那么我看不到任何方法。
答案 9 :(得分:0)
以下是另一个想法:如果条件(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);
}