0

何らかの理由で、my :: Vectorのオブジェクトを返したいと思います(これは基本的に、実際のストレージにSTLベクトルを内部的に使用し、いくつかの追加関数を提供するラッパークラスです)。関数が毎回ローカルでベクトルを作成するので、値ごとにベクトルを返します。

my::Vector<int> calcOnCPU()
{
  my::Vector<int> v....
  return v;
} 

これで、(ライブラリの設計を考慮して)関数呼び出しを複数回ネストできるようになったので、簡単に言うと次のようになります。

my::Vector<int> calc()
{
    if(...)
      return calcOnCPU();
}

AFAIK、値で返すと、my::Vectorクラスのコピーコンストラクターが呼び出されます。これは次のようなものです。

Vector<int>::Vector(const Vector& c)
{
   ....
   m_vec = c.m_vec; // where m_vec is std::vector<int>
}

いくつかの質問:1)コピーコンストラクターでは、std :: vectorのコピーコンストラクターを呼び出していますか?または代入演算子と確認のために、std :: vectorはディープコピーを作成します(基本的な整数型を考慮してすべての要素をコピーすることを意味します)。2)calc()にcalcOnCPU()をネストすると、それぞれがintのVectorを返します。Vectorの2つまたは1つのコピーが作成されますか?このような単純なメソッドのネストの場合、どうすれば複数のコピーを回避できますか?インライン関数または別の方法がありますか?

更新1:いくつかのカスタム要件があるため、独自のコピーコンストラクターを保持する必要があることが明らかになりました。ただし、main関数で簡単なテストを行いました。

int main() {
   ...
   my::Vector v = calc();
   std::cout<<v;
}

コピーコンストラクターで「std::cerr」を使用していくつかのプリントを配置し、いつ呼び出されるかを確認します。興味深いことに、上記のプログラムでは一度も呼び出されません(少なくとも何も印刷されません)。コピーエリジオン最適化ですか?LinuxでGNUC++コンパイラ(g ++)v4.6.3を使用しています。

4

1 に答える 1

2

コピーコンストラクターでは、std :: vectorのコピーコンストラクターを呼び出していますか?または代入演算子

あなたの場合、それは空を作成しstd::vector、それをコピーして割り当てます。イニシャライザリストを使用すると、リストが直接コピー構築されます。これは、より適切で、おそらくより効率的です。

Vector<int>::Vector(const Vector& c) : m_vec(c.m_vec) {
    ....
}

確認のために、std::vectorはディープコピーを作成します

はい、をコピーするstd::vectorと、新しいメモリブロックが割り当てられ、すべての要素がそのブロックにコピーされます。

calc()にcalcOnCPU()をネストすると、それぞれがintのVectorを返します。Vectorの2つまたは1つのコピーが作成されますか?

それはコンパイラー次第です。「戻り値の最適化」(コピーの省略の特殊なケース)を適用する必要があります。この場合、ローカルオブジェクトを作成してコピーを返すことはありませんが、返されたオブジェクトに割り当てられたスペースに直接作成します。これを実行できない場合があります。たとえば、複数のローカルオブジェクトの1つを返す可能性のある複数のreturnステートメントがある場合です。

また、最新のコンパイラは、コピーを省略できない場合でも、ベクトルのコンテンツがコピーされるのではなく、返されたオブジェクトに移動される移動セマンティクスもサポートします。つまり、メモリの割り当てや要素のコピーを行わずに、ベクトルの内部ポインタを設定することですばやく転送されます。ただし、ベクターを独自のクラスでラップしていて、コピーコンストラクターを宣言しているため、そのクラスを機能させるには、そのクラスに移動コンストラクターを指定する必要があります。これは、次の場合にのみ実行できます。 C++11を使用します。

このような単純なメソッドのネストの場合、どうすれば複数のコピーを回避できますか?インライン関数または別の方法がありますか?

関数の構造が、コピーの省略が機能するのに十分単純であることを確認してください。可能であれば、ベクトルを移動するmoveコンストラクターをクラスに指定します(または、コピーコンストラクターと、存在する場合は代入演算子を削除して、暗黙的に生成できるようにします)。インライン化によって違いが生じる可能性はほとんどありません。

于 2012-07-06T13:05:08.240 に答える