0

假设有一个类似的功能

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);
}
4

10 回答 10

2

我不是 100% 清楚你的意思,但如果你只是想Foo在返回值中省略不必要的副本,让你的函数变小(现在是这样)并依靠优化编译器来处理你的问题.

一旦函数被内联,编译器将删除不必要的Foo.

(感兴趣的注意:NRVO(命名返回值优化)不能在这里应用,因为没有唯一的名称可以分配给所有可能的返回值实例。)

于 2009-08-27T07:39:10.243 回答
1

如果你不想在堆中创建对象,那么你应该在调用函数之前创建它并在那里传递一个引用。想想临时的性质:函数在堆栈中创建新对象,然后返回,丢弃它的堆栈帧。所以对象应该在那里或者应该被复制到那里。

于 2009-08-27T07:45:53.037 回答
1

如果foo(在调用函数中)在调用后没有再次使用,您可以使用函数(如有必要swap专门std::swap用于类):Foo

const Foo& PreprocessFoo(Foo& f)
{
   if (something)
   {
      std::swap(f, Foo());
   }

   // return original or new object
   return f;
}
于 2009-08-27T08:38:57.300 回答
0

我能想到的唯一方法是返回一个 Foo 对象而不是引用。

于 2009-08-27T07:41:05.060 回答
0
Foo PreprocessFoo(const Foo& f)
{
   if (something)
   {
      // create new object
      return Foo();
   }

   // return original object
   return f;
}
于 2009-08-27T07:41:54.170 回答
0

您当前的解决方案有什么问题?Foo由于 RVO,可以省略复制构造函数。在执行函数时,对临时对象的引用将一直有效SendToTheWorld

于 2009-08-27T07:42:51.983 回答
0

如果你的 Foo 对象的生命周期不是由一段代码决定的,为什么不使用 ashared_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 ) );
于 2009-08-27T07:46:42.803 回答
0

您的要求是相互矛盾的:您希望对象是一个自动变量,但您希望对它的生命周期有发言权。不可能通过引用返回自动变量。你可以按价值退货,但这太贵了。我的想法:如果复制的成本如此之高,那么在免费商店上分配的成本可能与之相比很小。

您可以使用输出参数,并且大多数情况下不复制原始参数:

Foo& preProcess( Foo& f ) {
    if( something ) f=Foo(); // hopefully something is special!
    return f;
}

Foo localFoo;
SendToTheWorld( preProcess( localFoo ) );
于 2009-08-27T08:44:56.867 回答
0

这不是一件容易的事。

我看到了解决这个问题的三种方法,所有这些都归结为使复制更便宜。所有都需要控制Foo,一个PreprocessFoo也需要控制:

  1. 使用实现右值引用的编译器(C++1x 的一部分)并配备Foo必要的东西让它们启动并降低复制成本。
  2. 阅读Alexandrescu 的 mojo 文章并进行更改Foo以实现它。
  3. 使用程序员的万能疗法:添加另一层间接性。包装Foo在一些类似智能指针的对象中,这使得复制变得便宜。然而,这将需要动态分配。

如果你不能改变Foo,那我就没有办法。

于 2009-08-27T09:05:23.470 回答
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);
}
于 2009-08-27T09:12:54.780 回答