【问题标题】:Converting vector to array. How to deallocate memory?将向量转换为数组。如何释放内存?
【发布时间】:2016-10-21 22:37:26
【问题描述】:

我正在将一个双精度向量转换为一个双精度数组,如 here 所示:

不同的是,我想将指针 a 作为函数参数返回:

void getArray(double* a)
{
    std::vector<double> v;
    a = &v[0];
}

所以我的问题是,a 的内存何时被释放?还是我必须自己打电话给delete[] a,这看起来很奇怪,因为我没有用new分配内存。我已经阅读了上述答案的 cmets,但我仍然不清楚。

【问题讨论】:

  • a 将指向垃圾,一旦v 超出范围,则没有可删除的内容
  • 函数一返回,a 的内存就会被释放,因为a 是一个指向向量元素的指针,而“v”是函数的局部变量。
  • 另外,在 UB 旁边,从 c++11 开始,不那么骇人听闻的版本是 v.data() 而不是 &amp;v[0],请参阅 stackoverflow.com/a/10740171/104774
  • “我正在将一个双精度向量转换为一个双精度数组” - 为什么?
  • 无论如何,忘记getArray函数,只需在程序中使用向量并在不能使用向量的地方(例如C接口)使用v.data(),确保使用的数据在向量的时间线,这在您的示例中并非如此,正如 Andrew 的回答中已经提到的那样。

标签: c++ arrays pointers vector


【解决方案1】:

a 的内存什么时候被释放?

a 指针本身是一个局部变量,因此它会在其作用域结束时被释放。

a指向向量v分配的内存。指向的内存在v 的析构函数中被释放(如果对象被添加到向量或从向量中删除,内存也可能被释放)。并且因为v是一个局部变量,它在作用域结束时被销毁。

还是我必须自己调用 delete[] a,

不是,因为内存是vector对象所有的,也是因为

这似乎很奇怪,因为我没有用 new 分配内存。

没错。你没有打电话给new[],所以你没有打电话给delete[]


请注意,v[0] 具有未定义的行为,因为向量为空。

【讨论】:

    【解决方案2】:

    不要这样做:

    void getArray(double* a)
    {
        std::vector<double> v;
        a = &v[0];
    } // The vector is destroyed here, and the memory
      // is deallocated.
    

    在任何情况下,您都没有在函数之外修改 a 指针,因此您不会得到想要的效果。

    相反,返回vector 并直接使用它。或者,一般来说,在整个代码中使用向量。如果您需要将它们 in 传递给需要指向数组的指针的函数,则可以在那里传递 &amp;v[0]。这样的函数通常也需要大小。为此,请传递v.size()。只要该函数不占用所有权或释放内存,您就可以安全地执行此操作。

    还要注意,声明为std::vector&lt;double&gt; v; 的向量没有大小,因此尝试访问第一个元素,如v[0] 中的那样也是未定义的行为。至少,您需要给向量一个大小(将大小传递给它的构造函数)以确保分配一些内存。在对向量进行索引之前,应始终确保向量已分配一些内存,包括尝试获取第一个元素的地址时。

    你可能想做的是:

    std::vector<double> getArray() {
      std::vector<double> v = /* some sane initialisation */;
      return v;
    }
    
    // some time later, assuming a function:
    //   void do_something(double* a, size_t n);
    // ...
    
    std::vector<double> v = getArray();
    if (v.size()) {
      do_something(&v[0], v.size());
    } else {
      // fail gracefully
    }
    

    【讨论】:

      【解决方案3】:

      此实现将调用未定义的行为,因为 v 是本地的:

      void getArray(double* a)
      {
          std::vector<double> v;
          a = &v[0]; // would be a UB for returning the pointer to internals of a local variable.
      }
      

      但是,调用者将永远不会看到任何效果,因为对 a 的修改保留在 getArray 函数的本地。

      如果你想从一个向量中创建一个数组,分配一个新数组,使用std::copy将内容复制到其中,并将数组返回给调用者。确保调用者在完成 copyL 后在结果上调用 delete[]

      double *getArray(const vector<double>& v) {
          double *res = new double[v.size()];
          std::copy(v.begin(), v.end(), res);
          return res;
      }
      

      调用者应按如下方式使用它:

      vector<double> data;
      data.push_back(...);
      ... // populate the vector
      double *tmp = getArray(data);
      ... // Use the array
      delete[] tmp; // Avoid memory leaks
      

      【讨论】:

      • 我不认为有 ub,因为正如你所说,对 a 的任何修改都是函数本地的。
      • @tobi 访问 v[0] 的向量时存在 UB,该向量尚未构造大小。
      • @Andrew 啊对,我以为他指的是取消引用无效指针(实际上“...因为 v 是本地的”是误导)
      • 考虑以注释的形式添加方法文档。恕我直言,这是返回原始指针时的好习惯。
      【解决方案4】:

      当向量v 被破坏时,a 指向的内存被释放。在这种情况下,它位于函数 getArray 的末尾。

      【讨论】:

      • @Basilevs 取决于 OP 想要做什么。什么时候你想要内存被破坏?谁应该管理这个?
      • @Basilevs 内存管理的一个好方法是将向量保持为向量并让它管理内存,而不是自己手动管理它。这真的取决于最终目标。不应该做的事情的示例用法可能表明这是正确的做法。现代 C++ 程序员应该尽量避免使用原始指针。
      猜你喜欢
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 2011-01-06
      相关资源
      最近更新 更多