Search code examples
c++new-operatorheap-memorycopy-constructordelete-operator

How does an undefined new operator lead to undefined behaviour in C++?


Here I have a C++ code:

#include <iostream>
#include <map>
#include <string>
#include <cstdlib>

using namespace std;

class Person {
    private:
        int year;
        Person(const Person& pers);
    public:
        Person(int y): year(y)
        { cout << "Default constructor" << endl;}

        ~Person()
        {
            cout << "Destructor " << endl;
        }

        int get_year() const
        {
            return year;
        }
};


int main()
{
    map<string, Person*> test;
    test.insert(pair<string, Person*>("ini_1", new Person(2)));
    return 0;
}

Output

Default constructor
  1. From the output, I would like to know, how I can delete the value of test map given new Person(2) without coding it like first
Person* per = new Person(2)
test.insert(pair<string, Person*>("ini_1", per));

delete per;
  1. Without defining like this first
Person* per = new Person(2)
test.insert(pair<string, Person*>("ini_1", per));

Will it lead to undefined behaviour? Can you describe more detail of the undefined behaviour? Especially how does it exist in the memory? Thanks.

  1. If it is not correct, can I do like this which use Person instead new Person? Will it lead to any undefined behaviour?
#include <iostream>
#include <map>
#include <string>
#include <cstdlib>

using namespace std;

class Person {
    private:
        int year;

    public:
        Person(int y): year(y)
        { cout << "constructor" << endl;}

        Person(const Person& pers)
        {
            cout << "copy constructor" << endl;
        }
        ~Person()
        {
            cout << "Destructor " << endl;
        }

        int get_year() const
        {
            return year;
        }
};


int main()
{
    map<string, Person> test;

    test.insert(pair<string, Person>("ini_1", Person(2)));

    return 0;
}

Output:

constructor
copy constructor
copy constructor
Destructor
Destructor
Destructor
  1. I don't understand why the constructor ran for once and copy constructor ran for twice. Can you please explain where they happened?

Thanks.


Solution

  • From the output, I can see the destructor did not run. I would like to know, how I can delete the new pointer without defining it?

    You declared a map of ;pointers to Person

    map<string, Person*> test;
    

    So an object of the type Person is created only once in this statement

    test.insert(pair<string, Person*>("ini_1", new Person(2)));
    

    Further the map deals with the pointer not with the object.

    You will need to delete the created object explicitly. For example

    for ( auto &item : test )
    {
        delete item.second;
         item.second = nullptr;
    }
    

    If you will not delete the allocated object (or objects) then there will be a memory leak.

    I don't understand why the constructor ran for once and copy constructor ran for twice. Can you please explain where they happened?

    In this statement

    test.insert(pair<string, Person>("ini_1", Person(2)));
    

    the conversion constructor is called explicitly to create an object of the type Person Person(2).

    Then the copy constructor of the class Person is called to create an object of the type pair<string, Person>.

    And at last this object is copied to the map again calling the copy constructor of the type Person for the data member second of the pair.

    So three objects were created and three destructors for the objects were invoked.