1

Here is the code:

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;
    }

Output:

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

So if I'm not wrong, when I change an element of object array it does not call destructor. My first question is what happens to old object at the changed index? Does the array in it leak? I thought that I need to call destructor myself to prevent memory leak but it gives heap error. Second question is I'm getting heap error (Expression: _CrtlsValidHeapPointer(block)) when destructor of the changed object called. I have no idea why, it works fine for the ones created in constructor. Thanks!

6
  • 1
    Do note that if you are doing manual memory management in the class you need to follow the rule of 3 or 5. Commented Nov 29, 2016 at 16:48
  • 1
    I would imagine that anArr[0] = A(1) is equivalent to anArr[0].operator=(A(1)), which would construct a new A with id=1, call the copy constructor of anArr[0] with that A, id=1, then destruct A, id=1. The default implementation for A::operator= isn't going to manage your memory for you, so you leak. Solution: Implement the copy constructor or use std::vector/std::array Commented Nov 29, 2016 at 16:51
  • @NathanOliver thanks, i've never heard of them. Commented Nov 29, 2016 at 17:05
  • @Ics thanks, we are not allowed to use vector Commented Nov 29, 2016 at 17:05
  • @HalilİbrahimAzak if you haven't heard of them, then I would recommend you to study how manual dynamic memory allocation should be done, instead of trying to do it without knowledge, only to fall into the pitfalls. This might help: stackoverflow.com/questions/388242/… Commented Nov 29, 2016 at 17:08

2 Answers 2

3

My first question is what happens to old object at the changed index?

An object in an array never goes anywhere. The "old" object remains in that index. You invoke the assignment operator on that object. The assignment operator modifies the object.

Does the array in it leak?

The array that the object pointed to before the assignment does leak, yes.

I thought that I need to call destructor myself to prevent memory leak

You created the object with new[], so you do need to call delete[], which indeed calls the destructors.

but it gives heap error

That's because you forgot to follow the rule of 3 (or of 5).

anArr[2] contains the same pointer that the temporary A(2) contained, but since the destructor of the temporary has already run, it has already deleted the array and the destructor of anArr[2] then tries to delete it again. Which is one of the things that must not be done.


Conclusions:

  • When you do manual memory management, follow the rule of 3
  • Don't do manual memory management. Use std::vector or std::array here instead.
Sign up to request clarification or add additional context in comments.

Comments

1

What happens to the old object at the changed index?

It is re-assigned. In C++, this line

anArr[2] = A(1);

makes a new temporary object A(1), assigns that value into the existing object anArr[2], and destroys the temporary object. anArr[2] is the same object throughout, only its value changes. Since it is not newly created, it is also not destroyed at this point. But notice that the temporary object was destroyed, and deleted that brand new int[10] that anArr[2] thinks (mistakenly) that it owns.

When the value is a pointer to existing resources that need to be freed, you need to write a user-defined assignment operator, A::operator=(const A&). The "Rule of Three" says that most cases where you need a custom destructor, custom copy constructor, or custom copy assignment operator, you also need both the other two. (Since C++11, move constructor and move assignment are added to that list, making the "Rule of Five").

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.