【问题标题】:Delete a vector without deleting the array删除向量而不删除数组
【发布时间】:2017-04-06 05:51:51
【问题描述】:

我正在尝试在 C++ 中填充双精度向量并将关联的数组传递给 Fortran。但是我无法释放与向量相关的其余内存。我想避免复制。这是我所拥有的:

std::vector<double> *vec = new std::vector<double>();
(*vec).push_back(1.0);
(*vec).push_back(2.0);
*arr = (*vec).data();            //arr goes to Fortran

如何在保持arr 不变的同时删除vec?有没有办法使vec 中指向arr 的指针无效,以便我可以删除vec

更新

我发现我在这里没有提供足够的信息。几件事:

  1. 我实际上是在 Fortran 中使用 iso_c_binding 调用 C++ 函数
  2. 我不知道vec 需要多大。向量类看起来很适合这种情况

我最终可能会尝试 Guillaume 的建议,但现在,我将 vec 传递给 Fortran,并在完成数据处理后调用另一个 C++ 函数将其删除

【问题讨论】:

  • std::vector 不支持此功能。
  • 在 c++ 中,访问指针成员的首选方法是 -&gt; 运算符。 vec-&gt;push_back(1.0);.
  • 堆分配的 STL 容器是一个很好的方法。它们不适合多态性,并且与值语义很相配。执行new std::vector 是一种解决 STL 的所有不便的方式,但没有任何优势。
  • 为什么要用new 创建向量?这样做几乎没有任何充分的理由。
  • 至于默认向量自己管理内存,您需要编写自己的分配器。将向量的内容复制到数组中要容易得多。

标签: c++ pointers stdvector


【解决方案1】:

您需要重新考虑您的程序设计。

不知何故,在 Fortran 使用数组时,您需要在某个地方保持其活动状态。因此,无论您使用什么上下文访问 Fortran,都应该负责该数组的所有权。

class fortran_context {
    /*Blah blah blah whatever API you're using to access Fortran*/
    void * arr;
    std::vector<double> vec; //Don't allocate this as a pointer; makes no sense!
public:
    fortran_context() {
        arr = //Do whatever is necessary to setup Fortran stuff. I'm assuming your
        //api has some kind of "get_array_pointer" function that you'll use.
    }

    ~fortran_context() {
        //Do the cleanup for the fortran stuff
    }

    //If you want to spend time figuring out a robust copy constructor, you may.
    //Personally, I suspect it's better to just delete it, and make this object non-copyable.
    fortran_context(fortran_context const&) = delete;

    std::vector<double> & get_vector() {
        return vec;
    }

    std::vector<double> const& get_vector() const {
        return vec;
    }

    void assign_vector_to_array() {
        *arr = vec.data();
    }

    void do_stuff_with_fortran() {
        assign_vector_to_array();
        //???
    }
};

int main() {
    fortran_context context;
    auto & vec = context.get_vector();
    vec.push_back(1.0);
    vec.push_back(2.0);
    context.do_stuff_with_fortran();
    return 0;
} //Cleanup happens automatically due to correct implementation of ~fortran_context()

我已经抽象了很多这方面的内容,因为我不知道您使用什么 API 来访问 Fortran,而且我不知道您正在使用这个数组做什么类型的工作。但到目前为止,这是确保安全的最安全方法

  • 只要您在 Fortran 中执行操作,向量的分配内存就存在
  • 完成后,与向量关联的内存将被正确清理。

【讨论】:

    【解决方案2】:

    如何在保持 arr 不变的同时删除 vec?有没有办法在 vec 中取消指向 arr 的指针,以便我可以删除 vec?

    该库不提供任何内置功能来做到这一点。您必须自己做簿记工作。

    1. 为数据分配内存并从向量中复制数据。
    2. 将数据发送到 FORTRAN。
    3. 决定何时可以安全地解除分配数据,然后将其删除。

    // Fill up data in vec
    std::vector<double> vec;
    vec.push_back(1.0);
    vec.push_back(2.0);
    
    // Allocate memory for arr and copy the data from vec
    double* arr = new double[vec.size()];
    std::copy(vec.begin(), vec.end(), arr);
    
    // use arr
    
    // delete arr
    delete [] arr;
    

    【讨论】:

    • 需要注意的是,我们只是将生命周期管理问题从向量转移到向量的副本。为什么不首先在使用向量数据时防止向量被破坏?
    • @ChristopherPisz,如果 vec 是在调用 FORTRAN 的同一堆栈框架或范围内创建的,那就没问题了。
    • @R Sahu,对,他的 OP 中需要更多代码才能使其更有意义。只是想确保 OP 理解“在使用时不要破坏东西”的概念
    【解决方案3】:

    你所要求的是不可能的。 std::vector,作为一个表现良好的模板类,在销毁时会释放它拥有和管理的内部。

    当你使用它的内容时,你必须保持向量的活跃,这是非常有意义的。否则,您将不得不制作副本。

    另外,我不明白你为什么要在堆上分配向量,它似乎根本不需要。

    【讨论】:

    • 我正在使用 new 以便在 C++ 中超出范围后数据仍然可以在 Fortran 中访问
    • 向量上的新内容与 Fortran 中可用的数据无关。向量在内部为其内容分配内存,所有 STL 容器也是如此。
    • @ChristopherPisz vector 默认只自己管理内存,但也有可能通过非默认分配器提供外部内存管理。
    • @Logman,当然,可以提供自定义分配器,但这仍然与更新向量本身完全不同。无论哪种方式,vector 都通过调用分配器来分配和释放它们来管理其内部。
    【解决方案4】:

    如何在保持 arr 完整的同时删除 vec?有没有办法在 vec 中取消指向 arr 的指针,以便我可以删除 vec?

    你没有。


    我认为您误用或误解了矢量的用途。这并不是为了暴露底层数组的内存管理,而是将动态大小的数组表示为常规类型。

    如果您需要显式管理内存,我建议您使用std::unique_ptr&lt;T[]&gt;。由于唯一指针提供了一种管理内存和释放它的资源而不删除它的方法,我认为它是满足您需求的好选择。

    auto arr = std::make_unique<double[]>(2);
    arr[0] = 1.;
    arr[1] = 2.;
    auto data = arr.release();
    
    // You have to manage `data` memory manually,
    // since the unique pointer released it's resource.
    
    // arr is null here
    // data is a pointer to an array, must be deleted manually later.
    
    delete[] data;
    

    【讨论】:

    • 谢谢!这看起来正是我所需要的
    • 致反对者:这个答案有什么问题?它与 RSahu 答案非常相似,但使用唯一的 ptr 而不是原始数组。
    猜你喜欢
    • 2022-06-10
    • 2017-08-08
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多