1

「未使用」の動的オブジェクトのスタックがあるとします。新しいオブジェクトが必要になるたびに、この「未使用」オブジェクトの 1 つを新しい請願のプレースホルダーとして使用します。何かのようなもの:

template<typename T>
class my_list
{
public:
   template<typename... Args>
   T* newObject(Args&&... args)
   {
       if (unused.empty())
          return new T(forward<Args>(args)...);
       else {
          auto* newbie = unused.top();
          unused.pop();

          newbie = new (newbie) T(forward<Args>(args)...); // l. X

          return newbie;
       }
   }

private:
   stack<T*> unused;

};

問題は、行 X で、より効率的な文章、または次の文章です。

*newbie = std::move(T(forward<Args>(args)...));

つまり、newwith newbieas address の呼び出し (新しいメモリの要求を回避する) と、元のオブジェクトを上書きする新しい一時オブジェクトの移動のどちらがより時間効率がよいのでしょうか?

4

2 に答える 2

3

ここに別の実行可能なオプションがあります。完全な転送には C++11 がまだ必要ですが、移動の構築と代入を実装するために更新されていないライブラリ コードで動作するという利点があります。

T(forward<Args>(args)...).swap(*newbie);

さらに、move 割り当て呼び出しには既に一時オブジェクトがあるため、明示的に移動可能にする必要はありません。

*newbie = T(forward<Args>(args)...);

これらのいずれかにより、「最初に破棄してからインプレースで構築する」アプローチよりも、例外の安全性を提供することがはるかに簡単になります。

于 2013-03-11T15:05:26.877 に答える
2

moveコンストラクター呼び出しは prvalue 一時を作成するため、これは不要です。あなたの質問は、どちらがより効率的かということになります。

newbie->~T();
new (newbie) T(std::forward<Args>(args)...);

また

*newbie = T(std::forward<Args>(args)...);

適切に記述された移動代入演算子があると仮定するとT、ほとんど違いはありません。副作用に関しては、デストラクタはT、最初のケースではコンストラクタの前に呼び出され、2 番目のケースではコンストラクタの後に呼び出されますが、これが一方の方法でもう一方の方法よりもパフォーマンスに影響を与えると信じる理由はありません。後者は、よりプリミティブな値のコピーになる可能性がありますが、まともな最適化コンパイラはそれらを排除します。

前者がパフォーマンスを大幅に改善することを示すパフォーマンス テストがない場合は、後者の方がはるかに読みやすく、例外を安全にするのが簡単であるため、後者を優先する必要があります。

于 2013-03-11T15:05:15.700 に答える