Ricky
Ricky

Reputation: 883

How do I un-initialize an object in C++?

I'm not 100% certain I worded the title for this right so here's what I want to be able to do...

I have a class that gets defined like so...

class Animal
{
public:
    Animal() : m_name("New Animal")
    {
    }

    Animal(const std::string& name) : m_name(name)
    {
    }

    Animal(const Animal& animal) : m_name(animal.name)
    {
    }

private:
    const std::string name;
};

I then initialize an object of this class like so...

Animal* m_animal = new Animal("Leroy");

At some point in my program, the user will click a button that will cause m_animal to become empty. Meaning that the pet named Leroy should not longer exist..

I assumed I could use delete m_animal, but once I call this I can no longer use m_animal without causing a memory allocation error.

So I guess my question is... Would me using the following code cause a memory leak since the pet named Leroy was not deleted... and if so what are alternatives on how to get this done?

m_pet = NULL;

The entire process would look like this...

Animal* m_animal = new Animal("Leroy");
Animal* m_animal2 = new Animal("Boo");
std::cout << m_animal.name << endl;
m_animal = NULL;
m_animal = new Animal(m_animal2);
std::cout << m_animal.name << endl;

Upvotes: 0

Views: 172

Answers (5)

2785528
2785528

Reputation: 5566

Sometimes (but not for this mcve), it is simpler to use an init() method.

Though I prefer the initialization list such as you have used here (after the ctor), you will sometimes run into system start up sequence options where the ctor parameter is not yet available and thus can not be filled in by the ctor. This is a particular problem when two or more instances (of same or different class) have pointers to the other (as in working and protect hw control)

So, you might consider the following, which solves sequencing and mutual dependency challenges by providing an init() method.

class Animal
{
public:
    Animal()
    {
        init("New Animal")
    }

    Animal(const std::string name)
    {
        init(name);
    }

    Animal(const Animal& animal)
    {
        init(animal.m_name); 
    }

    void init(std::string name)
    {
       m_name.erase(); // clear the previous attribute 
       //           (not really needed here, but included for clarity)
       m_name = name;  // fill in new attribute 

       // and continue with both clear (when needed) and init's 
       // of all the other data attributes 
       // in an order similar to the initialization list.
       // note that the compiler won't be able to notify you
       // of out of order initialization issues.
   }

private:
    const std::string name;
};

So, is init() good for anything else?

You asked

how do I un-initialize an object.

In this case, you can simply use "init(...)" to simultaneously

a) clear out the previous state info (when necessary)

b) initialize the state info as if newly created

and

c) avoid the relatively costly delete and new of the other approach.

Upvotes: 1

moonwalker
moonwalker

Reputation: 1177

Since these two are pointers to Animal class. This should work too:

std::cout << m_animal->name << endl;
m_animal = m_animal2;
std::cout << m_animal->name << endl;

No need to allocate memory for an animal third time, even if one of them gets deleted before, its inefficient code. Then you should delete only one of these pointers and set them both to nullptr. Using an std::shared_ptr may be a more robust solution though.

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490048

You could just add a clear member function that (for example) sets the name to an empty string. This means "Leroy" no longer exists, but an Animal in a valid state exists, so you can use it to hold some other animal without deleting the old one and allocating a new one.

This, however, still leaves an Animal object--just one that doesn't have a name. If you want to separate allocation from creation/destruction of the objects in the memory, you can allocate raw memory with operator new, then use a placement new to create an object in that memory. When you want to destroy the object, you can directly invoke its destructor, which will truly destroy the object (but leave the memory allocated).

When you're done with the memory, you can use operator delete to delete the memory.

Aside: this is pretty much what std::vector, for one example, does with its memory block. While it's probably more useful when you're dealing with multiple objects, there's nothing particularly wrong with doing it for a single object either.

Aside #2: in most cases, you don't need (or really want) to use new or delete directly as you've shown above. In quite a few cases, you can use an std::shared_ptr or std::unique_ptr instead, with std::make_shared or std::make_unique to allocate the object.

Upvotes: 2

p.i.g.
p.i.g.

Reputation: 2985

If you create an object with the new operator, then you need to delete it with the delete operator.

Animal* animal = new Animal( "Pig" );

// Using the animal ...

delete animal;
animal = nullptr;

You need to use the new - delete pair to avoid memory leaks.

Upvotes: 0

Greg Hewgill
Greg Hewgill

Reputation: 992717

You do want to use delete m_animal;. You can do this:

std::cout << m_animal.name << endl;
delete m_animal;
m_animal = new Animal(m_animal2);
std::cout << m_animal.name << endl;

After calling delete m_animal, you can no longer use what m_animal pointed to, but you can certainly use the m_animal pointer again.

Upvotes: 4

Related Questions