C++:delete[] 错误,指针未分配

Posted

技术标签:

【中文标题】C++:delete[] 错误,指针未分配【英文标题】:C++: delete[] error, pointer not allocated 【发布时间】:2018-09-07 00:01:03 【问题描述】:

我正在为一个实验室开发一个程序,我需要一些有关内存管理的帮助。作为一个整体,我是 C++ 新手,虽然我有其他语言的经验,但动态内存管理让我感到困惑。另外,因为这是针对实验室的,所以我不能使用 std::vector 或智能指针,只能使用数组和指针。

首先,有一个“Vehicle”类,其中包含一些描述它的属性(例如品牌、型号等)。接下来,有一个“Showroom”类,其中包含一个 Vehicles 数组:

Vehicle * m_vehicles;

然后,在构造函数中:

m_vehicles = new Vehicle[m_maxCapacity];

接下来有一个“经销商”类,它有一个陈列室数组:

Showroom * m_showrooms;
...
m_showrooms = new Showroom[m_maxCapacity];

我的 main() 方法创建了一些车辆,将它们添加到陈列室,然后将它们添加到经销商处。在程序结束之前,一切正常。当程序完成并删除对象时,会出现一些问题。由于经销商是最后创建的,因此首先将其删除。它是析构函数调用delete[] m_showrooms;,Showroom 类中的析构函数调用delete[] m_vehicles;。所以,我希望当程序结束时,操作系统会删除经销商对象,​​从而删除陈列室对象,进而删除车辆对象。

但是,它不能正常工作。实验室要求我们使用已提供的帮助程序,将内存泄漏标记为错误。什么时候 我的 main() 创建了一个陈列室,向其中添加车辆,创建经销商,然后将陈列室添加到经销商,当程序结束时,内存泄漏检测器给出错误,说:

delete[] error: pointer was not allocated!

对于我添加到经销商的每个陈列室,我都会收到一次此错误。此外,还有一个奇怪的错误:如果经销商包含任何两个容量相同的陈列室,则程序结束时会出现段错误。

如果我说“搞砸”并从析构函数中删除所有 delete[],程序运行时不会出现段错误,但内存泄漏程序会检测到泄漏并阻止我继续前进。

我做错了什么?我对 C++ 中的动态内存有某种基本的误解吗?我读到每个 new[] 都应该与 delete[] 匹配,这就是我所拥有的。我已经问过我的 TA,她不知道如何解决。

编辑:以下是一些相关代码:

main.cpp:

//array of vehicles to store
Vehicle vehicles[] =
        
                Vehicle("Ford", "Mustang", 1973, 9500, 113000),
                Vehicle("Mazda", "CX-5", 2017, 24150, 5900),
                Vehicle("Dodge", "Charger", 2016, 18955, 9018),
                Vehicle("Telsa", "Model S", 2018, 74500, 31),
                Vehicle("Toyota", "Prius", 2015, 17819, 22987),
                Vehicle("Nissan", "Leaf", 2016, 12999, 16889),
                Vehicle("Chevrolet", "Volt", 2015, 16994, 12558),
         ;
    // Showrooms to store the vehicles
        Showroom showroom("Primary Showroom",2);
        showroom.AddVehicle(&vehicles[0]);
        showroom.AddVehicle(&vehicles[1]);
        //showroom.AddVehicle(&vehicles[2]);

        Showroom secondary("Storeroom 2",4);
        secondary.AddVehicle(&vehicles[3]);
        secondary.AddVehicle(&vehicles[4]);
        secondary.AddVehicle(&vehicles[5]);
        secondary.AddVehicle(&vehicles[6]);

        // A "parent" object to store the Showrooms
        Dealership dealership("Dealership",2);
        dealership.AddShowroom(&showroom);
        dealership.AddShowroom(&secondary);
        //displays the showrooms and their contents
        dealership.ShowInventory();

Vehicle.cpp 中的相关函数:

Vehicle::Vehicle(std::string mk, std::string md, int yr, int pr, int ml) 
    make = mk;
    model = md;
    year = yr;
    price = pr;
    miles = ml;


Vehicle::~Vehicle() 

Vehicle::Vehicle(const Vehicle &veh) 
    //year  = new int;
    make = veh.make;
    model = veh.model;
    year = veh.year;
    price = veh.price;
    miles = veh.miles;

Vehicle& Vehicle::operator=(const Vehicle &veh) 
    make = veh.make;
    model = veh.model;
    year = veh.year;
    price = veh.price;
    miles = veh.miles;
    return *this;

Vehicle::Vehicle() 

来自 Showroom.cpp:

//copy constructor
Showroom::Showroom(const Showroom &s)

    m_name = s.m_name;
    m_maxCapacity =s.m_maxCapacity;
    m_currentNumberOfVehicles = s.m_currentNumberOfVehicles;
    m_vehicles = new Vehicle[m_maxCapacity];

    for (int i = 0; i< s.m_currentNumberOfVehicles;i++)
    
        m_vehicles[i] = *new Vehicle(s.m_vehicles[i]);
    

//normal constructor
Showroom::Showroom(std::string name, unsigned int maxCapacity) 
    m_name = name;
    m_maxCapacity = maxCapacity;
    m_vehicles = new Vehicle[m_maxCapacity];

    m_currentNumberOfVehicles = 0;


Showroom::~Showroom() 
    delete[] m_vehicles;


Showroom::Showroom()

来自 Dealership.cpp:

//copy constructor
Dealership::Dealership(const Dealership &d)

    m_name = d.m_name;
    m_maxCapacity =d.m_maxCapacity;
    m_currentNumberOfShowrooms = d.m_currentNumberOfShowrooms;
    m_showrooms = new Showroom[m_maxCapacity];

    for (int i = 0; i< d.m_currentNumberOfShowrooms;i++)
    
        m_showrooms[i] = *new Showroom(d.m_showrooms[i]);
    

//normal constructor
Dealership::Dealership(std::string name, unsigned int capacity) 
    m_name = name;
    m_maxCapacity = capacity;
    m_currentNumberOfShowrooms = 0;
    m_showrooms = new Showroom[m_maxCapacity];

Dealership::~Dealership() 
    //std::cout<<"Deleting dealership " <<m_name << std::endl;
    delete[] m_showrooms;
    //m_showrooms = 0;


编辑 2:这是 main() 中最少的代码,它给出了错误,说我试图释放一个未分配的指针:

Showroom sh("Name", 0);

    Dealership dealer("dealer", 1);
    dealer.AddShowroom(&sh);

这是段错误的最少代码:

Showroom sh("Name", 0);
    Showroom sh2("Showroom 2",0);
    Dealership dealer("dealer", 2);

    dealer.AddShowroom(&sh);
    dealer.AddShowroom(&sh2);

这里是 AddShowroom(),供参考:

void Dealership::AddShowroom(const Showroom *showroom) 

    m_showrooms[m_currentNumberOfShowrooms] = *showroom;
    m_currentNumberOfShowrooms++;

【问题讨论】:

显示您的代码,而不是冗长的解释。听起来您确实没有正确删除数组(或者可能尝试删除它们两次)。 请提供您的代码。我的随机猜测是您不关注The Rule of Three,而是复制您的对象。如果您被允许并且已经了解它,std::unique_ptr 可能会解决所有问题。 你可能犯了一个常见的错误,那就是先编写一大堆代码,然后运行它,看看它是否有效。但如果没有,你真的不知道问题可能出在哪里。专业程序员不会一下子写完所有东西,然后调试它。他们一次只编写几行代码,然后运行、测试、验证它是否有效,然后编写接下来的几行代码。首先编写一个简短的程序,分配一些对象,使用它们,然后deletes 它们。一旦确保它正常工作,然后编写更多代码来创建更多对象等...... 我已经问过我的助教,她不知道如何解决 -- 不用说,你有麻烦了。 -- 我读到每个 new[] 都应该与 delete[] 匹配,这就是我所拥有的 -- 如果您将源代码计算在内,是的,它们可能匹配。但它远不止数字匹配。但是,如果您的逻辑导致delete[] 的调用次数比new[] 的调用次数多怎么办?或者,如果您丢弃了 new[] 给您的指针值,而是删除了与 new[] 值不匹配的指针值? 请发minimal reproducible example,强调最小化。删除尽可能多的代码,直到找到重现问题的最少量代码,然后发布。 【参考方案1】:

您的代码存在许多问题,它们都可能以某种方式导致段错误。

补充@ShadowRanger 所指出的,shsh2动态分配的,dealer 保留对它们的引用。这两个对象在超出范围时会自动销毁。因此,当这种情况发生时,dealer 将对不再存在的对象进行操作,并且会出现分段错误。

我看到的分段错误的另一个原因是由于m_showrooms 在超出其容量时没有调整大小。 m_showrooms = new Showroom[m_maxCapacity]; 行为Showroom 指针分配m_maxCapacity 的插槽数。当您调用AddShowroom 时,您需要检查是否会超出此容量。如果是这样,您需要分配一个更大的数组,将对象移过来,然后销毁旧数组(而不是它所容纳的对象)。

据我所知,您似乎不熟悉 C++ 中如何处理内存的想法。我建议花时间弄清楚这一点,因为它会为您省去很多麻烦。

【讨论】:

【参考方案2】:

这些行保证内存泄漏:

m_vehicles[i] = *new Vehicle(s.m_vehicles[i]);

和:

m_showrooms[i] = *new Showroom(d.m_showrooms[i]);

这是动态分配、解除引用,并使用解除引用的值将 assign 复制到数组中。但是指向原始动态分配值的指针立即丢失了;你在分配它的那一刻就泄漏了内存。

你真的想要:

m_vehicles[i] = Vehicle(s.m_vehicles[i]);

和:

m_showrooms[i] = Showroom(d.m_showrooms[i]);

您的段错误代码出现错误的原因很明显:

Dealership dealer("dealer", 1);

声称最多将分配一个陈列室,然后您调用AddShowroom 两次,并注销分配的内存的末尾(可能会损坏堆,并且谁知道还有什么)。

我不能确定为什么它会抱怨未分配的指针,但是你有这么多的泄漏和越界错误,你的代码省略了这么多,很难确定我没有错过任何东西,而不是有错误的代码可以检查。您遇到的这种错误可能是由堆损坏(您肯定在不同时间引起的)或双delete[]ing 指针引起的。没有明显的代码这样做,但您没有提供MCVE(您提供的既不是最小的也不是完整的),所以它可能被隐藏了。

【讨论】:

感谢您的反馈。我想我真的需要回顾一下指针等背后的基本概念。虽然这并不能真正为我提供答案,但我接受了它,因为我认为让这个问题保持开放是没有效率的。

以上是关于C++:delete[] 错误,指针未分配的主要内容,如果未能解决你的问题,请参考以下文章

[c++基础] delete 和 delete []的区别

C++ - 未分配被释放的指针

c++中new和delete的用法

Delete 无法识别 List 中的指针分配

将指针分配给指针(并将指针传递给类)时使用删除的 C++ 混淆

指针 && 动态内存分配