如果A std :: vector在被释放时返回值?

时间:2012-12-04 20:50:41

标签: c++ opencv stl

我无法理解在以下场景中如何释放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。

3 个答案:

答案 0 :(得分: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的{​​{1}}元素 - 这里的问题是,这将是不再存在的对象的地址。这是因为下次在循环迭代中重新分配curves时,向量的内容将不再存在,因此您存储的指针不指向有效对象 - 它们指向已经被销毁的对象。循环结束后,向量将包含最后调用cur_points时返回的内容。如果要确保所有CreatePolyPoints对象仍然存在于您调用cv::Point的位置,则应考虑通过引用将该向量传递给cv::fillPoly函数,而不是返回新的向量每次都有价值。这将确保您在循环结束后仍然存在通过CreatePolyPoints()添加的所有项目

答案 1 :(得分: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变量而不是通过一个临时的。这种最常见形式的优化被称为“返回值优化”,大多数(所有?)现代编译器经常这样做。当这种情况发生时(通常在这里),行为就像我在编辑之前所描述的那样。

答案 2 :(得分: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, ... );
}