繁体   English   中英

持续引用临时对象

[英]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

  1. 使用实现右值引用(C ++ 1x的一部分)的编译器,并为Foo配备必要的东西,以使它们生效并使复制便宜。
  2. 阅读Alexandrescu的mojo文章,并更改Foo来实现。
  3. 使用程序员的通用疗法:添加另一层间接。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM