0

次のシナリオでC++std::vectorコンテナがどのように解放されるかを理解するのに問題があります

void DoSomething()
{
   cv::Point ** curves;
   int * curve_sizes;
   num_curves = m_curves.size(); //member variable holdings curves
   curves = new cv::Point*[num_curves];
   curve_size = new int[num_curves];

   std::vector<cv::Point> cur_points;
   for(int i = 0; i < num_curves; ++i)
   {
     cur_points = CreatePolyPoints(m_curves[i]);
     curves[i] = &cur_points[0];
     curve_sizes = cur_points.size();
   }

   cv::fillPoly(m_roi, curves, curve_sizes, num_curves, ... );

   //Clear the dynamic data
   // Do i do aything here?   
   delete [] curves;
   delete [] curve_sizes;
}

std::vector<cv::Point> CreatePolyPoints(Curve curve)
{
   std::vector<cv::Point> points;

   //Do work here here
   while(something)
   {
     cv::Point cur_point;
     points.push_back(cur_point);
   }

   return points;
}

前もって感謝します。誰かが私の目標に興味がある場合:「n」曲線で定義されたポリゴンを指定してROIを生成します。

4

3 に答える 3

4

動的に割り当てられないため、スコープ外になるとすぐに破棄されます。あなたの場合、DoSomething()関数が終了した後、変数はスコープ外になります。ローカル変数は、ループ内で割り当てられcur_pointsたの戻り値を取得します。CreatePolyPoints()これが発生すると、の古いコンテンツは存在しなくなります。ベクターが再割り当てされるたびに、そのベクター内cur_pointsのオブジェクトのインスタンスが破棄されるため、これについて心配する必要はありません。Curve同様にcur_points、スコープ外になるとき。

編集:あなたはここで問題を抱えているようです

std::vector<cv::Point> cur_points;
for(int i = 0; i < num_curves; ++i)
{
   cur_points = CreatePolyPoints(m_curves[i]);
   curves[i] = &cur_points[0];    // <-- problem
   curve_sizes = cur_points.size();
}

ベクトル要素0のアドレスを各反復でのith要素に割り当てcurvesます-ここでの問題は、それがもはや存在しないオブジェクトのアドレスになることです。これは、ループの反復で次に再割り当てされると、ベクトルの内容が存在しなくなるcur_pointsためです。したがって、格納しているポインターは有効なオブジェクトを指していません。既に破棄されているオブジェクトを指しています。ループが終了すると、ベクターには、への最後の呼び出しで返されたコンテンツが含まれCreatePolyPointsます。cv::Point呼び出したポイントにすべてのオブジェクトがまだ存在することを確認したい場合はcv::fillPoly、を参照してベクトルを渡すことを検討する必要があります。CreatePolyPoints()毎回値で新しいベクトルを返すのではなく、関数。CreatePolyPointsこれにより、ループが終了した後も、追加したすべてのアイテムが引き続き存在するようになります。

于 2012-12-04T20:52:45.433 に答える
2

cur_points自動保存期間を持つ変数です。ここで宣言されたときに存在します。

std::vector<cv::Point> cur_points;

...そして、それが囲んでいるスコープが持続する限り持続します。

この場合の「囲んでいるスコープ」は関数void DoSomething()自体でcur_pointsあるため、関数が戻るとスコープ外になり (自動的に) 破棄されます。

編集さて、上記は簡単な答えです。一時的なものも含まれるため、完全な答えは実際にはもう少し複雑です。

関数CreatePolyPointsはこの値を返しvectorます。この関数と戻り値のセマンティクスに厳密に従うということは、pointsその関数内でローカルに作成されたオブジェクトがCreatePolyPoints戻り時に破棄され、新しい一時オブジェクトvectorが から構築されることを意味しpointsます。その一時的なものは、関数から実際に返されるものです。このテンポラリはcur_points(copy-assignemnt を介して) 変数にコピーされ、テンポラリは破棄されます。

これは多くの無駄なコピーですが、話にはもう少し続きがあります。C++ 標準にも規則 (「AS-IF」規則と呼ばれる) があり、コンパイラは、プログラムの動作がコンパイラの場合と同じである限り、適切と思われる方法でコードを変更できると述べています。副作用を考慮して変更はありませんでした。

上記が意味することは、コンパイラーには、このケースを含む多くの場合、これらすべての一時変数を削除するための主要な最適化の機会があるということです。これは、一時変数を介してではなく、戻り値を直接変数にコピーすることによって行われますcur_points。この最も一般的な形式での最適化は「戻り値の最適化」と呼ばれ、ほとんどの (すべて?) 現代のコンパイラは頻繁にこれを行っています。これが発生すると(通常はここで発生します)、動作はここで編集する前にレイアウトしたとおりです。

于 2012-12-04T20:55:06.740 に答える
0

リークせず、バグが削除されたDoSomethingの例を次に示します。

void DoSomething()
{
  std::vector<std::vector<cv::Point>> curves;
  // so long as I do not resize this, or change its length,
  // curves[x].data() will remain valid
  curves.resize( m_curves.size() );

  for(int i = 0; i < num_curves; ++i)
  {
    curves[i] = CreatePolyPoints(m_curves[i]);
  }
  // create buffers of the correct size for the legacy API:
  std::vector<v::Point*> curve_ptrs(curves.size());
  std::vector<int> curve_sizes(curves.size());
  for(int i = 0; i < curves.size(); ++i)
  {
    curve_ptrs[i] = curves[i].data();
    curve_sizes[i] = curves[i].size();
  }

  // call the legacy API:
  cv::fillPoly(m_roi, curve_ptrs.data(), curve_sizes.data(), num_curves, ... );
}
于 2012-12-04T21:29:29.823 に答える