动态数组 - 内存管理问题

Posted

技术标签:

【中文标题】动态数组 - 内存管理问题【英文标题】:Dynamic Array - Problem with memory management 【发布时间】:2021-12-05 23:02:29 【问题描述】:

我正在研究动态数组。数组类相关部分代码:

#pragma once
#include <iostream>

template <class T>
class Darray


private:
    T* dataArray;
    int a_size = 0;
    int a_capacity = 0;
    double expandFactor = 1.5;

private:
    void memLoc(int n_capacity)
    
        T* newArray = new T[n_capacity];

        for (int i = 0; i < a_size; i++)
        
            newArray[i] = dataArray[i];
        

        
        dataArray = newArray; 
        delete[] newArray; //<-- **************problem occurs here**************
        a_capacity = n_capacity;
        
        
    

public:
    Darray()
    
        T* dataArray = new T[a_size];
        memLoc(2);
    

    void addLast(T data) 
    
        if (a_size < a_capacity)
        
            dataArray[a_size] = data;
            a_size++;
        
        else
        
            memLoc(a_capacity * expandFactor);
            dataArray[a_size] = data;
            a_size++;
        
    

当我运行代码而不删除 newArray 我得到预期的结果:

Values
Index 0: 10
Index 1: 9
Index 2: 8
Index 3: 7
Index 4: 6
Index 5: 5
Index 6: 4
Index 7: 3
Index 8: 2
Index 9: 1

这是我的问题!当我删除 newArray(在代码中标记)时,我的结果远非准确:

Values
Index 0: -572662307
Index 1: -572662307
Index 2: 100663302
Index 3: 31812
Index 4: 17648624
Index 5: 17649832
Index 6: -572662307
Index 7: -572662307
Index 8: -572662307
Index 9: -572662307

我不知道为什么会这样,因为乍一看一切似乎都是正确的。任何建议或提示将不胜感激。我希望有人能够提供帮助;)

【问题讨论】:

您不应该删除旧数组,而不是刚刚分配的新数组吗? 恕我直言,您最好花时间了解std::vector,而不是编写自己的动态数组类。 @Frank 我使用 dataArray 作为类的属性,因此我创建了更大尺寸的新数组,复制它,然后将值传递给 dataArray。在代码中:dataArray = newArray。此时 newArray 在内存中未使用,因此我想删除它。我错过了什么吗?因为我不知道为什么会这样。如果我错了,请纠正我。 @ThomasMatthews 我已经看到了,这要容易得多,但这是拼贴的任务,他们希望我们这样做:/ @Swagelele 这不是指针的工作方式。 dataArraynewArray 不是数组本身,它们是数组的指针。所以在dataArray = newArray之后,它们都指向同一个数组:新的。 【参考方案1】:

您的代码中有几个错误。

memLoc() 中,您正在销毁刚刚创建的new 数组。您需要销毁被替换的 old 数组。语句dataArray = newArray; 只是将一个指针 分配给另一个指针dataArray 指向前一个数组,newArray 指向新数组。当您执行dataArray = newArray; 时,您会泄漏先前的数组,现在dataArraynewArray 都指向同一个数组,然后delete[] newArray; 销毁该数组,留下dataArray 作为指向无效内存的悬空指针.

在您的默认构造函数中,您正在创建一个新数组并将其指针分配给名为dataArray 的局部变量,该变量隐藏了也名为dataArray 的类数据成员。然后调用memLoc() 为类数据成员dataArray 创建另一个数组以指向。第一个数组没用并被泄露。您应该将类​​数据成员初始化为nullptr,然后调用memLoc() 来创建唯一的数组。

此外,虽然这些不是错误的说法,但它们值得注意:

我假设您未显示的其余代码符合Rule of 3/5/0,即您有一个析构函数、复制/移动构造函数和复制/移动赋值运算符。如果没有,请确保您解决了这个问题,否则您以后会遇到其他问题。

addLast()中的代码是重复的,可以简化。

话虽如此,试试这个:

#pragma once
#include <iostream>
#include <utility>

template <class T>
class Darray

private:
    T* dataArray = nullptr;
    int a_size = 0;
    int a_capacity = 0;
    static const double expandFactor = 1.5;

private:
    void memLoc(int n_capacity)
    
        T* newArray = new T[n_capacity];

        for (int i = 0; i < a_size; ++i)
        
            newArray[i] = dataArray[i];
        

        delete[] dataArray;
        dataArray = newArray; 
        a_capacity = n_capacity;
    

public:
    Darray()
    
        memLoc(2);
    

    Darray(const Darray &src)
    
        memLoc(src.a_capacity);
        for (int i = 0; i < src.a_size; ++i)
        
            dataArray[i] = src.dataArray[i];
            ++a_size;
        
    

    Darray(Darray &&src)
    
        std::swap(dataArray, src.dataArray);
        std::swap(a_capacity, src.a_capacity);
        std::swap(a_size, src.a_size);
    

    ~Darray()
    
        delete[] dataArray;
    

    Darray& operator=(Darray rhs)
    
        std::swap(dataArray, rhs.dataArray);
        std::swap(a_capacity, rhs.a_capacity);
        std::swap(a_size, rhs.a_size);
        return *this;
    

    void addLast(const T &data) 
    
        if (a_size >= a_capacity)
            memLoc(a_capacity * expandFactor);
        dataArray[a_size] = data;
        ++a_size;
    

    ...
;

【讨论】:

以上是关于动态数组 - 内存管理问题的主要内容,如果未能解决你的问题,请参考以下文章

C语言之动态内存管理(动态内存分配+经典笔试题+柔性数组)[建议收藏]

⭐️欢度国庆-共约C语言进阶⭐️ 动态内存管理+柔性数组 建议收藏

动态内存管理与柔性数组

剖析c语言动态内存管理

动态内存管理

C语言篇 + 内存管理及柔性数组话题