Reputation: 883
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
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
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
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
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
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