C++: Deallocating dynamic memory when derived class object is destructed - c++

I seem to have an issue with dynamic memory allocation.
Below you'll see a derived class that contains a pointer for a name variable that will be dynamically allocated using the void name(const char* name) method. The function is run by the Product constructor, which sets a name for the product class when the object is created. Here's the class:
namespace sict {
class Product :public Streamable {
char* name_;
public:
Product(const char* name);
virtual ~Product();
void name(const char* name);
}
And here's the name function itself, along with the one argument constructor:
void sict::Product::name(const char * name) {
int g = strlen(name);
name_ = new char[g];
strncpy(name_, name, g);
name_[g] = 0;
}
Product::~Product() {
delete [] name_;
name_ = nullptr;
}
To me this code seems capable enough of created the object then destroying it peacefully whenever it exits the scope of the function it's running in. However, when the function ends and the destructor runs, the program freezes/crashes at delete [] name_. Running the program on Visual Studio's compiler seems to yield no particular errors (other than the program freezing), but the gcc compiler detects some sort of heap corruption. Would anybody know why this is happening?

I'm not sure why Sean Cline didn't post his comment as an answer, but Sean is correct.
name_ is given g elements and then name_[g] is set to zero, but name_[g] is one past the end of the array. Either use name_ = new char[g+1]; or name_[g-1] = 0; so that you don't go past the end of the array.
Also, as several comments point out, any time you have a class that allocates memory dynamically, make sure you define the copy constructor, the assignment operator, and the destructor. If you miss one, the default implementation will perform a shallow copy, which can cause headaches for you.
A shallow copy is when the pointer is copied instead of the data it points to. In your case, if an object of this class is ever copied or assigned, you end up with two objects pointing to the same data on the heap, and they would both try to delete it when they run their destructors.
For more information on those functions, see the Rule of Three

Related

Clear map of dynamic values in C++

I've seen many sites talking about the correct way to implement a d'tor for a class that holds a map.
But not for the case where the values of the map themselves are dynamically allocated.
For example, let Manager be a class which hold map<int, User*> where User is some class which I'll allocate dynamically later.
By the rules of the exercise, it should handle a registerUser(string name) function, which creates a new User instance and adds it to the map.
Something like:
User* registerUser(std::string userName) {
User* pNewUser = new User(userName);
// Setting some stuff
auto ret = users.insert(std::pair<int, User*>(pNewUser->id, pNewUser));
// Finishing and returning a pointer to the new allocated User
}
AND TO THE QUESTION ITSELF:
Should the d'tor do something special beyond users.clear()?
Will the memory be freed successfully or shall I iterate over the elements and delete them?
Thank you in advance :)
Don't use pointers when you do not have to. The std::map already manages the lifetime of its elements for you:
struct User {
std::string name;
int id;
static int id_counter;
User(const std::string& name) : name(name),id(id_counter++) {}
};
struct manager {
std::map<int,User> users;
User& registerUser(std::string userName) {
User u(userName);
auto ret = users.emplace(u.id,u);
return ret.first->second;
}
};
If you are forced to use a std::map<int,User*> because of weird unrealistic exercise requirements (or because the map is supposed to hold polymorphic objects) and you cannot use smart pointers then you need to delete what you newed. The map only manages its elements, not what they might point to:
struct manager {
std::map<int,User*> users;
User& registerUser(std::string userName) {
User* u = new User(userName);
auto ret = users.emplace(u->id,u);
return *(ret.first->second);
}
~manager() {
for (const auto& user : users){
delete user.second;
}
}
// the compiler generated assignment and copy would not do the right thing
manager(const manager&) = delete;
manager& operator=(const manager&) = delete;
};
Not sure where you read about holding a map as member and needing to call clear(). That is non-sense. The map has a destructor that is called automatically and the map does already clean up after itself.
Last but not least, you need to read about the rule of 3 (What is The Rule of Three?), because a destructor alone is not sufficient to correctly manage raw pointers as members. As mentioned in a comment, when you copy the manager via the compiler generated copy constructor or assignment, bad things will happen. Note that this isnt the case with the first version above. When possible you should try to follow the rule of 0 (https://en.cppreference.com/w/cpp/language/rule_of_three scroll down).
Should the d'tor do something special beyond users.clear()?
In general that depends on how your code handles ownership of heap allocated objects; any time you call a constructor by new (aka allocate on the heap) you should be aware of wich component in your code takes ownership over the newly created object and in consequence is responsible for deletion of the object.
For this specific toyproblem your Manager class should also handle the deletion of the object by iterating over all elements in your favourite way and calling delete. Be aware some other component could still hold onto one of these User-pointers wich will cause a crash by accessing invalid memory in the best case and running fine until it shipped in the worst case (or starting a nuclear war, since this is in the scope of undefined behaviour). The state of the art solution is using some kind of smart pointer.
Of course as 463035818_is_not_a_number put it so nicely in his answer you don't need to call users.clear(). Since the map will be deleted automagically since it is a statically allocated variable (but not necessarily the contents of the map).

C++ pass pointers to a Template class function

I am new to C++ (more of a java guy). I am trying to teach myself about C++ pointers. Here I've created two classes, Person (The base class), and the Student (Derived class).
I tried to put Student objects in an unordered_map<string, Person>. But met an error.
This is my code:
class Person
{
protected:
string name;
int age;
public:
int getAge()
{
return age;
}
string getName()
{
return name;
}
};
class Student : public Person
{
private:
string grade;
public:
Student(string const &name, int const &age, string const &grade)
{
this -> name = name;
this -> age = age;
this -> grade = grade;
}
int getAge();
};
Here's my main function:
int main()
{
unordered_map<string, Person *> students;
Student s("Sam", 26, "A");
Person *p;
p = &s;
students.insert(p -> getName(), p);
return 0;
}
This is just a part of the code, and I know it looks foolish. But I'm just learning about pointers
I have included <iostream> and <unordered_map> libraries and using namespace std here.
Error message is so long. Can someone point out the error I made here ? Or, should I post that long error message also ?
Thanks in advance.
I am more of a java guy.
Here's what you need to know:
Pointers
Person* is a pointer to a person - a pointer simply carries the address of an object in memory. It's as low level as you can get. It's equivalent to using an address register or index register in assembly language. It carries no information about object lifetime and does not influence object lifetime in any way. It is 100% abusable. Use with care, if ever.
Shared references
// java code
var x = new Y();
var y = x;
// equivalent c++
auto x = std::make_shared<Y>();
auto y = x;
If you want java-like behaviour, then std::shared_ptr<Person> is equivalent to a java object reference. It shares ownership of the person and allows (actually in c++ mandates) that the Person is destroyed when all of the shared_ptrs have gone out of scope or have been reset.
Unique reference with lifetime control
Between the two is a std::unique_ptr<Person> which will cause the automatic destruction of the Person when the one and only unique_ptr is destroyed or reset. You cannot copy a std::unique_ptr so it can't be used to share references to an object. It can however, be converted to a shared_ptr (this implicitly empties the unique_ptr).
Weak references
Then there is a std::weak_ptr<Person> which is the weak counterpart to a std::shared_ptr<Person>. It cannot be de-referenced directly but must first be converted to a shared_ptr with the lock() method. This provides an atomic 'test for existence and lock into place' operation. We use it to resolve or avoid resource leaks caused by circular references (which java claims not to have on account of garbage collection).
Lifetime differences between Java and C++
In Java, when there are no more reachable references to an object, it becomes a candidates for garbage collection. At some point in the future, it may or may not be recovered.
C++ is different and more predictable. When the unique_ptr or the last shared_ptr controlling an object's lifetime is reset, that object's destructor will be executed immediately and in the same thread. It's completely sequential. This gives rise to the possibility of RAII, and allows us to use object lifetimes to cause code to execute no matter what the execution path.
This is also arguably why there is no need for finally in c++. Resource cleanup goes in the destructors of resource owners.
int main()
{
unordered_map<string, Person *> students;
Student s("Sam", 26, "A");
Person *p;
p = &s;
pair<string, Person*> item("key", p);
students.insert(item);
return 0;
}
Your code looks ok, except for one line:
students.insert(p -> getName(), p);
Here you probably meant that you want to place p to the cell p->getName(), but, unfortunately, std::unordered_map::insert has no instance to take a key and a value as two arguments. Passing them as one argument or using operator[] should help:
students[p->getName()] = p;
students.insert({p->getName(), p});
students.insert(std::make_pair(p->getName(), p));
I personally would select first option as more readable, if possible.
UP: As #Jarod42 commented, the first option here requires the value type to be default constructible, which is not always an option.

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

Debug Assertion Error - delete call on char pointer

So I decided to dwelve a bit within the pesty C++.
When I call the delete function on a pointer to a simple class that I created I'm greeted by a Debug Assertion Failure -Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse). I assume this is because I've handled the string manipulation wrong and thus causing memory corruption.
I created a basic class, [I]animal[/I], that has a string defined that can be set through a function.
// name
char * ptrName;
animal::animal(char * name)
{
this->SetName(name);
};
animal::~animal()
{
delete [] ptrName;
}
void animal::SetName(char * name)
{
ptrName = name;
};
When using the above class as shown below the error occurs. I've tried both delete ptrName and delete [] ptrName but to no avail.
animal * cat = new animal("Optimus Prime");
delete cat;
What am I missing?
The string "Optimus Prime" was not dynamically allocated, and thus it is not correct to call delete on it.
The problem comes from deleting a pointer that you don't own. You haven't allocated the string, so you must not delete it. The C string you are using is allocated statically by the compiler.
The problem is that in the setName function you are merely assigning the name to ptrName. In the example, the name is a const char string pointer which you can't delete (it is not allocated on the heap). To avoid this error, you can either use a std::string in the class or allocate a new char arry in the constructor of the animal class and assign the pointer to it. Then, in the destructor you can delete the array.
So I decided to dwelve a bit within the pesty C++.
Then do yourself a favor and use C++ right. That would be to use std::string:
// name
std::string name_;
animal::animal(const std::string& name)
: name_(name)
{
}
//animal::~animal() // not needed any longer
//note: copying also automatically taken care of by std::string
//animal(const animal&)
//animal& operator=(const animal&)
void animal::SetName(const std::string& name)
{
name_ = name;
}
Have a look at The Definitive C++ Book Guide and List. I'd recommend Accelerated C++. It comes with a steep learning curve, but since you already know a bit of C++, it's the 250 pages that might set you on the right track.
As a rule of thumb: Whenever you release a resource (memory or other), and it's not in the destructor of a class whose solely purpose is to manage this one resource, something is wrong with your design. Personally, I become suspicious whenever I feel the need to write a destructor, copy constructor, or assignment operator.
Who has ownership of your string?
For example, when you construct your new animal, you're passing in a string literal - that's not yours to free.
You should consider avoiding char* and just using std::string instead.
If you have to use char*, think about ownership. For example, one option is for you to take a copy of the string (using strdup) and own that. This way you can't be stuck with strange bugs like this
char* szFoo = strdup("my string");
{
animal a(szFoo);
}
// At this point szFoo has been deleted by the destructor of a
// and bad things will start to happen here.
printf("The value of my string %s",szFoo);

Proper way to reassign pointers in c++

EDIT: I know in this case, if it were an actual class i would be better off not putting the string on the heap. However, this is just a sample code to make sure i understand the theory. The actual code is going to be a red black tree, with all the nodes stored on the heap.
I want to make sure i have these basic ideas correct before moving on (I am coming from a Java/Python background). I have been searching the net, but haven't found a concrete answer to this question yet.
When you reassign a pointer to a new object, do you have to call delete on the old object first to avoid a memory leak? My intuition is telling me yes, but i want a concrete answer before moving on.
For example, let say you had a class that stored a pointer to a string
class MyClass
{
private:
std::string *str;
public:
MyClass (const std::string &_str)
{
str=new std::string(_str);
}
void ChangeString(const std::string &_str)
{
// I am wondering if this is correct?
delete str;
str = new std::string(_str)
/*
* or could you simply do it like:
* str = _str;
*/
}
....
In the ChangeString method, which would be correct?
I think i am getting hung up on if you dont use the new keyword for the second way, it will still compile and run like you expected. Does this just overwrite the data that this pointer points to? Or does it do something else?
Any advice would be greatly appricated :D
If you must deallocate the old instance and create another one, you should first make sure that creating the new object succeeds:
void reset(const std::string& str)
{
std::string* tmp = new std::string(str);
delete m_str;
m_str = tmp;
}
If you call delete first, and then creating a new one throws an exception, then the class instance will be left with a dangling pointer. E.g, your destructor might end up attempting to delete the pointer again (undefined behavior).
You could also avoid that by setting the pointer to NULL in-between, but the above way is still better: if resetting fails, the object will keep its original value.
As to the question in the code comment.
*str = _str;
This would be the correct thing to do. It is normal string assignment.
str = &_str;
This would be assigning pointers and completely wrong. You would leak the string instance previously pointed to by str. Even worse, it is quite likely that the string passed to the function isn't allocated with new in the first place (you shouldn't be mixing pointers to dynamically allocated and automatic objects). Furthermore, you might be storing the address of a string object whose lifetime ends with the function call (if the const reference is bound to a temporary).
Why do you think you need to store a pointer to a string in your class? Pointers to C++ collections such as string are actually very rarely necessary. Your class should almost certainly look like:
class MyClass
{
private:
std::string str;
public:
MyClass (const std::string & astr) : str( astr )
{
}
void ChangeString(const std::string & astr)
{
str = astr;
}
....
};
Just pinpointing here, but
str = _str;
would not compile (you're trying to assign _str, which is the value of a string passed by reference, to str, which is the address of a string). If you wanted to do that, you would write :
str = &_str;
(and you would have to change either _str or str so that the constnest matches).
But then, as your intuition told you, you would have leaked the memory of whatever string object was already pointed to by str.
As pointed earlier, when you add a variable to a class in C++, you must think of whether the variable is owned by the object, or by something else.
If it is owned by the object, than you're probably better off with storing it as a value, and copying stuff around (but then you need to make sure that copies don't happen in your back).
It is is not owned, then you can store it as a pointer, and you don't necessarily need to copy things all the time.
Other people will explain this better than me, because I am not really confortable with it.
What I end up doing a lot is writing code like this :
class Foo {
private :
Bar & dep_bar_;
Baz & dep_baz_;
Bing * p_bing_;
public:
Foo(Bar & dep_bar, Baz & dep_baz) : dep_bar_(dep_bar), dep_baz_(dep_baz) {
p_bing = new Bing(...);
}
~Foo() {
delete p_bing;
}
That is, if an object depends on something in the 'Java' / 'Ioc' sense (the objects exists elsewhere, you're not creating it, and you only wants to call method on it), I would store the dependency as a reference, using dep_xxxx.
If I create the object, I would use a pointer, with a p_ prefix.
This is just to make the code more "immediate". Not sure it helps.
Just my 2c.
Good luck with the memory mgt, you're right that it is the tricky part comming from Java ; don't write code until you're confortable, or you're going to spend hours chasing segaults.
Hoping this helps !
The general rule in C++ is that for every object created with "new" there must be a "delete". Making sure that always happens in the hard part ;) Modern C++ programmers avoid creating memory on the heap (i.e. with "new") like the plague and use stack objects instead. Really consider whether you need to be using "new" in your code. It's rarely needed.
If you're coming from a background with garbage collected languages and find yourself really needing to use heap memory, I suggest using the boost shared pointers. You use them like this:
#include <boost/shared_ptr.hpp>
...
boost::shared_ptr<MyClass> myPointer = boost::shared_ptr<MyClass>(new MyClass());
myPointer has pretty much the same language semantics as a regular pointer, but shared_ptr uses reference counting to determine when delete the object it's referencing. It's basically do it yourself garbage collection. The docs are here: http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm
I'll just write a class for you.
class A
{
Foo * foo; // private by default
public:
A(Foo * foo_): foo(foo_) {}
A(): foo(0) {} // in case you need a no-arguments ("default") constructor
A(const A &a):foo(new Foo(a.foo)) {} // this is tricky; explanation below
A& operator=(const &A a) { foo = new Foo(a.foo); return *this; }
void setFoo(Foo * foo_) { delete foo; foo = foo_; }
~A() { delete foo; }
}
For classes that hold resources like this, the copy constructor, assignment operator, and destructor are all necessary. The tricky part of the copy constructor and assignment operator is that you need to delete each Foo precisely once. If the copy constructor initializer had said :foo(a.foo), then that particular Foo would be deleted once when the object being initialized was destroyed and once when the object being initialized from (a) was destroyed.
The class, the way I've written it, needs to be documented as taking ownership of the Foo pointer it's being passed, because Foo * f = new Foo(); A a(f); delete f; will also cause double deletion.
Another way to do that would be to use Boost's smart pointers (which were the core of the next standard's smart pointers) and have boost::shared_ptr<Foo> foo; instead of Foo * f; in the class definition. In that case, the copy constructor should be A(const A &a):foo(a.foo) {}, since the smart pointer will take care of deleting the Foo when all the copies of the shared pointer pointing at it are destroyed. (There's problems you can get into here, too, particularly if you mix shared_ptr<>s with any other form of pointer, but if you stick to shared_ptr<> throughout you should be OK.)
Note: I'm writing this without running it through a compiler. I'm aiming for accuracy and good style (such as the use of initializers in constructors). If somebody finds a problem, please comment.
Three comments:
You need a destructor as well.
~MyClass()
{
delete str;
}
You really don't need to use heap allocated memory in this case. You could do the following:
class MyClass {
private:
std::string str;
public:
MyClass (const std::string &_str) {
str= _str;
}
void ChangeString(const std::string &_str) {
str = _str;
};
You can't do the commented out version. That would be a memory leak. Java takes care of that because it has garbage collection. C++ does not have that feature.
When you reassign a pointer to a new object, do you have to call delete on the old object first to avoid a memory leak? My intuition is telling me yes, but i want a concrete answer before moving on.
Yes. If it's a raw pointer, you must delete the old object first.
There are smart pointer classes that will do this for you when you assign a new value.