释放与 C++ 中的结构关联的所有内存

Posted

技术标签:

【中文标题】释放与 C++ 中的结构关联的所有内存【英文标题】:Deallocating all memory associated with a struct in C++ 【发布时间】:2019-04-23 19:46:02 【问题描述】:

我有一个结构体,里面有几个向量,定义如下:

#include <vector>
using namespace std;

struct data
    vector<float> x;
    vector<float> y;
    vector<float> z;

我稍后会这样使用:

data d;
for(int i; i<3; i++)
    d.x.push_back(i)
    d.y.push_back(i*2)
    d.z.push_back(i*3)

现在我想安全地删除data,以完全释放与其关联的所有内存。我认为这样做的方法是编写一个简单的析构函数来清除和释放data的每个字段,然后delete对象:

struct data
    vector<float> x;
    vector<float> y;
    vector<float> z;

    ~data()
        vector<tempObject>().swap(x);
        vector<tempObject>().swap(y);
        vector<tempObject>().swap(z);
    

然后这应该可以工作:

data d;
    for(int i; i<3; i++)
        d.x.push_back(i)
        d.y.push_back(i*2)
        d.z.push_back(i*3)
    
delete data;

我使用最佳答案here 来释放向量。

这行得通吗?如果不是,您能否描述原因和/或提出替代方案?我知道一旦d 离开范围,内存将被释放,但我需要在此之前释放内存。

【问题讨论】:

您永远不必担心清理std::vector 的内存,除非您竭尽全力提供错误的分配器。 不需要删除,因为你有“data d”作为堆栈对象。矢量(因为大多数其他 stl 容器会为您进行清理)。如果您使用现代 c++ 并在 shared_ptr 或 unique_ptr 上管理堆对象,您(几乎)永远不需要使用关键字 new 和 delete delete data; 没有意义。 @FrançoisAndrieux 什么是糟糕的分配器? 你只有deletenewed。你没有new 任何东西所以不要delete 任何东西。 【参考方案1】:

struct 被销毁时,其成员将被销毁(以声明的相反顺序)。这样被销毁的vectors 将清理它们自己的内存。

不需要自定义析构函数。

【讨论】:

我该如何正确销毁structd?另外,你的第二句话是真的吗?在我的问题中链接到的 SO 问题的讨论表明并非如此。 @Anonymous 当d 超出范围时,它不再存在。 vector 内部的d 也是如此。 "我该如何正确销毁 struct d?" - 在您显示的代码中,d 在超出范围时将被自动销毁 - 在。是的,销毁std::vector 将释放其内存真的 - 无论您的实现是否选择保留该内存以用于将来的分配或将其返回给操作系统完全是另一回事。操作系统选择如何处理实现选择回馈的内存也是如此。这不是 C++ 关心的事情。【参考方案2】:

现在我想以一种完全释放与其相关联的所有内存的方式安全地删除数据。

在 C++ 中,变量具有自动、静态和动态存储持续时间。您在示例中和静态的自动存储持续时间的生命周期由编译器控制,因此您无法更改它们的生命周期(小例外是通过引用延长右值,但这与此处无关)。如果您需要手动控制生命周期,则需要创建一个具有动态存储期限的变量:

auto d = std::make_unique<data>();
d->x.push_back(1.0);
...
d.reset(); // terminate of lifetime of variable pointed by d manually

【讨论】:

【参考方案3】:

不需要删除,因为你有“data d”作为堆栈对象。

vector(因为大多数其他 stl 容器会为您负责清理工作)。

您也不需要结构的自定义析构函数

如果您使用现代 c++ 并在 shared_ptr 或 unique_ptr 上管理堆对象,您(几乎)永远不需要使用关键字 new 和 delete。

示例:

#include <vector>
#include <memory>

struct MyData

    std::vector<float> x;
    std::vector<float> y;
    std::vector<float> z;
;

int main()

    //example 1: stack object
    
        MyData d;
        for(int i = 0; i<3; i++)
        
            d.x.push_back(i);
            d.y.push_back(i*2);
            d.z.push_back(i*3);
        
     // scope of d ends, everything including the vectors are cleaned up


    //example 2: heap object  
    
        std::unique_ptr<MyData> dataPtr = std::make_unique<MyData>();
        for(int i = 0; i<3; i++)
        
            dataPtr->x.push_back(i);
            dataPtr->y.push_back(i*2);
            dataPtr->z.push_back(i*3);
        
     // scope of dataPtr ends, everything will be cleaned up

    //example 3: heap object, clean up within scope
    
        std::unique_ptr<MyData> dataPtr = std::make_unique<MyData>();
        for(int i = 0; i<3; i++)
        
            dataPtr->x.push_back(i);
            dataPtr->y.push_back(i*2);
            dataPtr->z.push_back(i*3);
        

        dataPtr.reset(); // this will clean-up whatever the pointer points to

     // scope of dataPtr ends, ptr itself is destoryed


【讨论】:

如果我想在d 离开范围之前清理它怎么办?当然,我可以以这样的方式重新组织我的代码,但这将意味着移动数百行(目前,在创建 d 的点和我的点之间声明了许多新对象。我希望它被释放,并且在整个程序中都需要这些对象) @Anonymous 你所说的“清理”到底是什么意思?由于d 仍在范围内,因此仍可访问。您是否希望在范围内有一个无效的垃圾对象,如果访问会导致不可预测的行为?你想节省一点内存吗? (如果是这样,只需将 clear(或 reset)函数添加到 struct 清空所有向量并调用该函数。对象仍然有效,但向量将为空。) @DavidSchwartz 我希望节省大量内存,更准确地说。 d 的内容>100TB,在读入后移动到另一个结构中,以方便一些 MPI 通信。简而言之,我使用struct d 仅用于读入,需要在将数据复制到其他地方后将其清除。不过,也许最好的解决方案就是重新构建代码,以便作用域处理所有这些。 为范围内的清理添加了示例 3。请注意,在 reset() 之后取消引用指针会使程序崩溃。 如果要传递数据,请使用 unique_ptr 或 shared_ptr。这样您就可以节省一些复制操作。修改数据时还要考虑就地转换。

以上是关于释放与 C++ 中的结构关联的所有内存的主要内容,如果未能解决你的问题,请参考以下文章

内存分哪些区 C++,ios,java

C++ 删除不会释放所有内存 (Windows)

关于结构体中内存的释放问题

在 C++ 中的 2D 动态内存分配数组中释放分配的内存

在 C 和 C++ 中如何分配和释放 *array* 内存?

C++动态内存管理与源码剖析