删除对象数组

时间:2016-11-29 16:47:18

标签: c++

以下是代码:

class A {
    private:
        int *anArr;
        int id;
    public:
        A() {
            id = 0;
            anArr = new int[10];
        }
        A(int i) {
            id = i;
            anArr = new int[10];
        }
        ~A() {
            delete[] anArr;
            std::cout << "Class A id : " << id << " destructor" << std::endl;
        }
    };

    class B {
    private:
        A *anArr;
    public:
        B() {
            anArr = new A[10];
        }
        ~B() {
            std::cout << "Class B destructor" << std::endl;
            delete[] anArr;
        }
        void changeAnElement() {
            anArr[2] = A(1);
            anArr[2] = A(2);
        }
    };

    int main()
    {
        B b;
        b.changeAnElement();

        return 0;
    }

输出:

Class A id : 1 destructor
Class A id : 2 destructor
Class B destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
// Gives heap error here

因此,如果我没有错,当我更改对象数组的元素时,它不会调用析构函数。 我的第一个问题是在更改的索引处旧对象会发生什么?它中的阵列是否泄漏?我以为我需要自己调用析构函数来防止内存泄漏,但它会给出堆错误。 第二个问题是当调用更改对象的析构函数时,我遇到堆错误(Expression: _CrtlsValidHeapPointer(block))。我不知道为什么,它适用于在构造函数中创建的那些。 谢谢!

2 个答案:

答案 0 :(得分:2)

  

我的第一个问题是在更改的索引处旧对象会发生什么?

数组中的对象永远不会出现在任何地方。 &#34; old&#34;对象仍然在该索引中。您在该对象上调用赋值运算符。赋值运算符修改对象。

  

它中的数组是否泄漏?

对象在赋值之前指向的数组确实泄漏了,是的。

  

我认为我需要自己调用析构函数来防止内存泄漏

您使用new[]创建了对象,因此您需要调用delete[],它确实会调用析构函数。

  

但它给出了堆错误

那是因为你忘了关注rule of 3 (or of 5)

anArr[2]包含与临时A(2)包含的指针相同的指针,但由于临时的析构函数已经运行,它已经删除了数组,然后anArr[2]的析构函数尝试再次删除它。这是必须要做的事情之一。

结论:

  • 进行手动内存管理时,请遵循3
  • 规则
  • 不要进行手动内存管理。请改为使用std::vectorstd::array

答案 1 :(得分:1)

  

更改索引时旧对象会发生什么?

重新分配。在C ++中,这一行

anArr[2] = A(1);

创建一个新的临时对象A(1),将该值分配给现有对象anArr[2],并销毁临时对象。 anArr[2]始终是同一个对象,只有它的值会发生变化。由于它不是新创建的,因此此时也不会被销毁。但请注意,临时对象已被销毁,并删除了int[10] 认为(错误地)拥有的全新anArr[2]

当值是指向需要释放的现有资源的指针时,您需要编写用户定义的赋值运算符A::operator=(const A&)。 &#34;三法则&#34;说大多数需要自定义析构函数,自定义复制构造函数或自定义复制赋值运算符的情况,您还需要其他两个。 (从C ++ 11开始,移动构造函数和移动赋值被添加到该列表中,制作&#34;规则为五&#34;)。