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::swapFoo

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オブジェクトの存続期間を1つのコードだけで決定しない場合は、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 ) );
于 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

これは簡単なことではありません。

これを解決するには 3 つの方法があると思いますが、いずれもコピーのコストを下げることにつながります。すべてが を制御する必要がFooあり、1 つはPreprocessFooも制御する必要があります。

  1. 右辺値参照 (C++1x の一部) を実装するコンパイラを使用し、Fooそれらを起動してコピーを安価にするために必要なものを装備します。
  2. Alexandrescu のモジョの記事を読んで、それFooを実装するように変更してください。
  3. Programmer's Universal Cure を使用します。間接的なレイヤーをもう 1 つ追加します。Fooコピーを安価にするスマート ポインターのようなオブジェクト内にラップします。ただし、これには動的割り当てが必要です。

変更できない場合Fooは、方法がわかりません。

于 2009-08-27T09:05:23.470 に答える
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

現在のソリューションの何が問題になっていますか? FooRVO により、コピー コンストラクターが省略される可能性があります。SendToTheWorld関数が実行されている間、一時オブジェクトへの参照は常に有効です。

于 2009-08-27T07:42:51.983 に答える
0

ここにもう 1 つのアイデアがあります。条件 ( something) がコンパイル時に修正されている場合は、それを へのテンプレート パラメータにすることができますPreprocessFoo()。次に、TMP を使用して、戻り値の型が異なる 2 つの異なる関数に分岐できます。

これがそのスケッチです:

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 に答える