How to properly write a destructor for this - c++

I have a simple struct, friends would be allocated with new, so obviously I need to delete that. However, with name and email I am not so sure.
struct Member
{
char * name;
char * email;
LinkedList<Member> * friends;
Member() : name(nullptr), email(nullptr), friends(nullptr)
{
}
~Member()
{
if (friends)
delete friends;
}
};
What if, for example, I have
Member m;
m.name = "John Doe";
m.email = "johnDoe0#email.com";
Do I still need to delete name/email?

The rule of thumb is: Only delete what you new (and delete[] what you new[]).
In this case you do not allocate memory for the character pointers, you make them point to constant arrays of characters instead, so you should of course not delete them.
Also note that it's valid to do delete on a nullptr.

Try to use std::string instead of char*. That will solve your problem. Otherwise this will be cumbersome ... you will need a flag to let the destructor know how the name was allocated (via new via *alloc or just a plain constant) and act accordingly (ie: if it was alloc'ed the free it if it was new'd then delete it, if it was initialized via a constant... you don't have to do anything).

You could work with a class instead of a structure, with attributes like name email .. etc, and then you'll just have to delete the entire member ?

Related

Memory management of class object attributes in C++

I'm sorry if this question was asked before. I searched the internet but couldn't find any clear answer.
Here is the issue :
Let's say I have a public class called Object that has 2 attributes. One is int attr1 and the other one is char * attr2. The constructor is (I have a header file) :
Object::Object(int param1, char * param2)
{
attr1=param1;
attr2 = new char[strlen(param2)+1]; // I understand that by doing this the values are stored in the heap
strcpy(attr2, param2);
}
I understand that in the destructor of the class Object I need to write delete [] attr2.
In another file, main.cpp I create a new object this way :
char * name = "Aname";
Object myObject = new Object(3, name);
From what I've understood, whenever new is used, the value is stored in the heap. Therefore a delete is necessary in order to avoid memory leaks.
Here I have used the new operator to create an Object. Therefore myObject is a pointer to an Object stored in the heap. I will need to do this : delete myObject when I will no longer need it.
So this is my question : since the object that myObject points to is stored in the heap, does that mean that all it's attributes are stored in the heap (including attr1 which is simply an int) ?
If so, how come I don't have to free it as well (meaning use the operator delete for it in the destructor) ?
Thank you for you help!
Note : english is not my first language, sorry for the mistakes.
The code you showed in your second example will not compile, because
myObject is not declared as a pointer
in C++11 and later, a non-const char* pointer cannot point to a string literal.
So you need this instead:
Object::Object(int param1, const char * param2)
{
attr1 = param1;
attr2 = new char[strlen(param2)+1];
strcpy(attr2, param2);
}
const char * name = "Aname";
Object * myObject = new Object(3, name); // <-- note the * !
That being said, the rest of your comments are correct. Since myObject is being created with new, its data members reside in dynamic memory (ie, the heap), and you must call delete myObject to destroy it and free its memory when you are done using it. And since you are directly allocating memory for attr2 with new[], you need to manually call delete[] attr2 to free it.
However, you are NOT directly allocating memory for attr1 with new, so you DO NOT need to manually call delete attr1. The memory for attr1 is managed by the compiler and will be released automatically when myObject is destroyed.
In short, when something is allocated explicitly by a function/operator, it must be deallocated explicitly with a corresponding function/operator, eg:
when something is explicitly allocated with the C++ new or new[] operator, it must be explicitly deallocated with the delete or delete[] operator, respectively.
if something is explicitly allocated with the C runtime (m|c|re)alloc() funtion, it must be explicitly deallocated with the C runtime free() function.
if something is explicitly allocated with the Win32 API (Local|Global)Alloc() or (Local|Global)ReAlloc() function, it must be explicitly deallocated with the Win32 API (Local|Global)Free() function.
etc

Deleting a dynamically allocated array from a function that initiates it C++

I'm writing a program in C++ that has to use dynamically allocated arrays from various structures (in separate files). A lot of times, I need to initiate these arrays inside of a function. Usually after initiating them, I write data to the array of a structure, or even an array inside of an array of structures, and then use the data later on. Therefore I don't use delete inside of the function.
For example, here is one of the structures that I use, a student structure:
struct Student {
int id; // student ID
char gradeOption; // either G or P
double totalScore;
std::string studentName;
int* rawScores = NULL; // array that holds raw scores for a student
// if no scores are entered for a specific ID, we check for NULL
// we can then set the scores to 0
std::string* finalGrade; // final grade given in course
};
And here is the function to input raw scores.
// input raw scores for each id
void inputRawScores(int gradedArtifacts, int id, Student* student) {
student[id].rawScores = new int[gradedArtifacts];
for(int i = 0; i < gradedArtifacts; i++) {
std::cin >> student[id].rawScores[i];
}
}
In my driver file, students also gets initialized with a value. Shown here:
Student* students = new Student[numOfStudents]; // array of students
The problem is is that I use these raw scores, and the array of students for calculations in a separate file, and use them for output in other files, and in other methods. How would I go about deleting any of these?
Also I realize that using delete will delete the structure and the pointers inside of the structure, but not the objects that the pointers point to. So I'm assuming this ties back into the first question and I can't just issue a delete at the end of my program.
Edit: I'm sorry, as many others have pointed out I should have stated the restraints that I have on the project. I'm not allowed to uses: classes, vectors, functions inside of structs (like constructors, destructors).
Don't do that.
Your system is badly designed, your struct should be a class and internally handle the rawScores memory - using a std::vector would be the easiest part, but even if you use regular pointers, the key is that the information about how many there are, and where they are stored, should be tracked in a class.
In other words, the student structure should keep track of HOW MANY elements there are, and allocate/deallocate the memory as needed. It should not be done in the function inputRawScores - that function may well call the function for setNumRawScores and call the function for setRawScore(n, value), but not allocate memory in the reader function. That belongs as a member function in the student structure. Then introduce a destructor method for your student, that is responsible for deallocating the memory.
Of course, using std::vector will "hide" all this from you, and you just have to set the size (or use push_back).
Given your newly posted constraints, I think you could just implement a deletion-function to traverse through the Student array and do manual cleanup.
First, we create a function that deletes the dynamic objects of one single student. Note that we could have used Student&as the parameter type, but given the information in your question I am not sure if you have learned references yet, or if you are allowed to use them. So we stick with the pointer:
void cleanupStudent(Student* student) {
delete[] student->rawScores;
delete student->finalGrade;
// EDIT: Setting pointers back to NULL after deletion provides
// some improved safety and is good practice.
student->rawScores = NULL;
student->finalGrade = NULL;
}
After that we create a function that allows you to delete the complete Student array by looping through all the items in the array and calling the cleanup function:
void deleteStudents(Student* students, int studentCount) {
for(int i = 0; i < studentCount; i++) {
cleanupStudent(&students[i]);
}
delete[] students;
}
Here, please note the ampersand-symbol (&students[i]) which we require to get a pointer to the object (which is required as a parameter to the cleanup function). After that, the student array itself is deleted.
You can call these functions like this:
int numOfStudents = 16;
Student* students = new Student[numOfStudents];
deleteStudents(students, numOfStudents);
Or with a single student:
Student* student = new Student;
cleanupStudent(student);
delete student;
As you might have noticed we sometimes use delete and sometimes delete[]. The first one just deallocates memory that has been allocated with new. The latter does the same thing to memory that has been allocated with new[]. This is very important to get right, otherwise you will get runtime errors. Also, make always sure that EVERY pointer in your struct is initialized wih NULL (C) or nullptr (C++).
Since it seems that you are just learning C/C++ it is crucial to mention that the above code is very unsafe, and you could get into real problems if e.g. the studentCount is not matching the actual number of items in the array. But for now I guess you wouldn't know (or aren't allowed) to do better.
EDIT: I noticed that your finalGrade member is of type std::string*. Is there a reason for this to be a pointer? Because if you just want to store a string, you can just do a std::string, no reason there to be a pointer. Please don't confuse a C-String of type char* with a STL string std::string.
This answer is obsolete since the owner of this questions specified some constraints that do not allow constructors/destructors.
As far as I unterstand your question, you do not know how to delete the actual dynamically allocated rawScores and finalGrad objects in your Student object, right? If so, the answer is quite simple, you just use a Destructor:
struct Student {
int id; // student ID
char gradeOption; // either G or P
double totalScore;
std::string studentName;
int* rawScores = nullptr;
std::string* finalGrade = nullptr;
// Disable copy and move assignment
Student& operator=(const Student& rhs) = delete;
Student& operator=(Student&& rhs) = delete;
// Disable copy and move construction
Student(const Student& rhs) = delete;
Student(Student&& rhs) = delete;
Student() {
// Initialize members.
}
// Destructor
~Student() {
delete[] rawScores;
delete finalGrade;
}
};
As soon as you deallocate a Student object using the delete operator:
Student* students = new Student[numOfStudents];
delete[] students; // <-- deallocation
The destructor is called for each object, which in turn will delete the dynamically allocated objects inside.
You don't have to bother if the pointers are NULL or not, calling delete on a pointer that is NULL is valid. Also, please initialize ALL pointers initially with nullptr when constructing the object (as shown above).
As long as you are not mixing runtimes accross different EXE/DLL boundaries you can delete the Student array from anywhere in your program, not matter in which file you allocate/deallocate it.
I hope this answers your question. If not, please be more specific about the problem you have.
EDIT: As pointed out in the comments, you should disable copy/move semantics if you are doing it this way (or implement them). But disabling them would practically pin you to dynamic allocation of the Student struct and give you less flexibility with most of the STL containers. Otherwise you could also use an std::vector instead of dynamically allocated arrays as pointed out in the other anwers.
It would be very tedious to effectively delete everything you hve allocated using new in this case as you are passing pointers to other modules/functions.
You have two options over here:-
Either replace those dynamic arrays ( rawscores/finalGrade ) with corresponding vectors.
You can use smart pointers ( I think auto_ptr would suffice if you are not using containers ) to take care of memory mangement.
EDIT:-
One main issue you have to handle if you are creating raw student pointer is of ownership. Let's say you have allocated memory to Student* and then you are passing this object to several modules/functions. You need to take into account that you don't call delete when your pointer is still in use in some other module. Also it should also not call delete when it's already deleted in some module. That's why I pointed you to two options...

C++ / destructor - operator delete

I was wondering if I have to delete this pointer in example like this :
class Person
{
public:
Person(char *name) :_name(name) {}
// Is this delete necessary?
~Person() {
cout<<"Godbay Person"<<endl;
delete _name;
}
private:
char * _name;
}
This is pretty surely wrong in any case.
There are two possibilities:
The name is created on the free store exclusively for your object, and your object has to assume ownership. Then the name has to be deleted.
The name is not created on the free store (e.g. as a string litaral, which is quite possible), or some other object is managing the name, so your object should not assume ownership. Then any deletion would wreak havoc with your program.
So why do I say its wrong even in the first case? Because name sounds like a string, not a single character, wich means name* will point to an dynamically alocated array of characters. In that case, the correct way to delete it would be delete[] name.
But: If possible, avoid using plain (char) pointers, for case 1. Use some memory management class instead (a string class or smartpointers), to get rid of the headaches of manually managing memory ownership. delete and delete[] should appear only seldom in your code except if you don't have access to up-to-date C++ compilers.
It is a matter of who owns the allocated memory, in this case it looks like Person is not owning it so then no, so there is no need to delete. Using raw pointers like you do in Person always give rise to questions about ownership, that is why it is recommended to use shared_ptr/unique_ptr instead or even better std::string since it seems to be a string.
Generally, you have to call delete each time you create a pointer with new.
It depends on creation procedure.
In this case no:
Person *p = new Person("John");
In this case yes:
char *str = new char[32];
::strcpy(str, "John");
Person *p = new Person(str);
In this case yes, but with ::free function rather than operator delete.
char *str = (char *)::malloc(32);
::strcpy(str, "John");
Person *p = new Person(str);
Consider using std::string instead of C string pointer.

Destructor does not destroy objects

I have written a small program, but main destructor is not working properly. Here is the code of the program:
#include<iostream.h>
class citizen {
private:
char* name;
char* nationality;
public:
citizen(char* name, char* nationality) {
this->name = name;
this->nationality = nationality;
}
citizen(const citizen &obj) {
name = obj.name;
nationality = obj.nationality;
}
void display() {
cout << "Name: " << name << endl;
cout << "Nationality: " << nationality << endl;
}
~citizen() {
if(name){
delete[]name;
}
if(nationality) {
delete []nationality;
}
}
};
main() {
citizen obj1("Ali", "Pakistani");
obj1.display();
{
citizen obj2 = obj1;
}
obj1.display();
system("pause");
}
What I know is that in main function where I'm assigning state of obj1 to obj2, from that place both of them are now pointing to same memory area. Whereas the code citizen obj2 = obj1; is between two curly braces.
{
citizen obj2 = obj1;
}
So after execution of second curly brace, obj2 should destroy and also delete variables name and nationality. And when I call obj1.display(); for the second time it should display garbage on the screen.
But obj1 is still printing exact name which I have provided in constructor, even though it shouldn't be.
Please explain this behavior.
Your delete[]s invoke undefined behavior because you're attempting to destroy string literals. Anything can happen.
Even if you allocated memory yourself, you'd still run into undefined behavior because you'd be attempting to access memory you've already deleted:
obj1.display();
{
citizen obj2 = obj1;
}
obj1.display(); // ILLEGAL
Because you didn't define an assignment operator, the compiler-generated one will be used, which just assigns the pointers to the same memory - memory which you destroy and then attempt to access.
This code is faulty.
if(name){
delete[]name;
}
if(nationality){
delete []nationality;
}
You are deleting, something which you have not allocated on heap, using the new operator.
Your copy constructor just copies the pointers (as the implicit one would do, if you hadn't provided your own), meaning that both objects will try to delete the same arrays. Additionally, you're setting the pointers to point to string literals, which must not be deleted at all; you must only delete objects that you created with new. The simple solution is to delegate memory management to a class designed to do that correctly:
std::string name;
std::string nationality;
Now you don't need to bother with your own destructor, copy constructor or copy-assignment operator; and as a bonus, your class will also be correctly movable in C++11.
If you enjoy dealing with memory issues yourself, then you'll need your constructors to allocate new buffers and copy the contents across. Be careful with exception safety, since you're trying to juggle two separate dynamic resources in one class, which is invariably a recipe for errors. You'll also need a copy-assignment operator (per the Rule of Three), and for efficiency you might also consider a move constructor and move-assignment operator.
Also, it might be worth updating to one of this century's versions of the language. <iostream.h> hasn't been a standard header for about fifteen years.
Others have pointed out the string related error but I think you're making a much more fundamental mistake: delete does not destroy things*; it merely frees up the memory for reuse and calls the relevant destructor. This means that its often entirely possible to use deleted objects after the delete operation without getting garbage back.
*- On some implementations, in __DEBUG mode it will stamp on released memory to allow you to spot these errors but this isn't part of the standard.
you should only delete block of memory that was dynamically allocated in the class using new operator
citizen(char* aname, char* anationality){
size_t nameSize = strlen(aname)
size_t nationalitySize = strlen(anationality)
this->name = new char[nameSize];
this->nationality = new char[nationalitySize];
strcpy(this->name, aname, nameSize);
this->name[nameSize ] = NULL;
strcpy(this->nationality , anationality , nationalitySize);
this->nationality [nationalitySize] = NULL;
}
if you create a memory in constructor, then you delete them in destructor.
and because you have some assignment, then you should implement a copy constructor, WHICH create a memory and copy the data on the right side of the = operator
final thought, you are better off using a string object if you cant deal with pointers to avoid memory leaks
It's pure luck that your second display call works.
As Jack Aidley points out, delete does not literally delete the values, just marks the memory region as usable. Thus, if no other application allocates and modifies that freed region, the previous values may stay there. Furthermore, after the deletion you still keep the pointers to that addresses.
In summary, you're accessing the same memory region having old values in it. But it's just luck because that region didn't modified by anybody.
To prevent these kinds of errors, you should always assign NULL to the unused pointers so that next time you get Access Violation error when you try to access them. Some compilers (such as MSVC) rewrite the freed memory with a signature value (such as 0xDDDDDD) so that during debugging you can catch the problems easily. Check this answer for details
Finally, delete should match to new otherwise the behavior is undefined so it's again just luck. I can't even run your application and display results. It keeps crashing and giving memory errors.
Thanks everybody. I have replace this code of constructor
citizen(char* name, char* nationality) {
this->name = name;
this->nationality = nationality;
}
with this code
citizen(char* name, char* nationality){
this->name = new char[strlen(name)+1];
strcpy(this->name, name);
this->nationality = new char[strlen(nationality)+1];
strcpy(this->nationality, nationality);
}
and finally it works fine. thanks

C++: Union Destructor

A union is a user-defined data or class type that, at any given time, contains only one object from its list of members. Suppose all the possible candidate members are needed to be allocated dynamically. For Eg.
// Union Destructor
#include <string>
using namespace std;
union Person
{
private:
char* szName;
char* szJobTitle;
public:
Person() : szName (nullptr), szJobTitle (nullptr) {}
Person (const string& strName, const string& strJob)
{
szName = new char[strName.size()];
strcpy (szName, strName.c_str());
szJobTitle = new char [strJob.size()];
strcpy (szJobTitle, strJob.c_str()); // obvious, both fields points at same location i.e. szJobTitle
}
~Person() // Visual Studio 2010 shows that both szName and szJobTitle
{ // points to same location.
if (szName) {
delete[] szName; // Program crashes here.
szName = nullptr; // to avoid deleting already deleted location(!)
}
if (szJobTitle)
delete[] szJobTitle;
}
};
int main()
{
Person you ("your_name", "your_jobTitle");
return 0;
}
Above program get crashed at 1st delete statement in ~Person (at moment when szName contains valid memory location, WHY?).
What will be the correct implementation for the destructor?
Same way, how to destruct a class object, if my class contains an union member (how to wrtie destructor for class including a Union)?
You can only use one member of the union at a time because they share the same memory. In the constructor, however, you initialize both members, which overwrites each other, and then in the destructor you end up releasing it two times. You're trying to use it as if it were a struct (based on the names of the fields you need to use a struct).
Nevertheless, if you need a union then you probably need a struct as a kind of envelope which has some id representing the member being used, as well as a constructor and a destructor that handles the resources.
Also - your arrays are too small. size() returns the number of characters, but if you use char* as your string type then you need space for the null-character (\0) to handle termination.
If you need unions, try using Boost.Variant. It is a lot easier to use than normal unions.
You're using delete when you should use delete [], because you have used new [], not new.
Change these:
delete szName;
delete szJobTitle;
to these:
delete [] szName;
delete [] szJobTitle;
By the way, the if condition in the destructor is pointless. I mean, if a pointer is nullptr, then it is safe to write delete ptr;, that is,
A *ptr = nullptr;
delete ptr; //Okay! No need to ensure ptr is non-null
Apart from that, you're violating rule of three (or five, in C++11):
What is The Rule of Three?
Rule-of-Three becomes Rule-of-Five with C++11?
Implement them.
You don't respect that new-delete pairing: new pairs with delete, new[] pairs with delete[]. You're doing new[], but calling delete; that's incompatible.
As a side note, the constructor has a memory leak: the memory assigned to szName is never freed once that pointer is overwritten by the assignment to szJobTitle).
And as this is C++, you should generally be using std::string instead of char* for strings.
Above program get crashed at 1st delete statement in ~Person (at moment when szName contains valid memory location, WHY?).
I don't have a compiler with me (or time to compile your code) but (apart from the problems addressed by Nawaz) I would guess it's because you treat the union members as class members. In your union, szName and szJobTitle should be looked like two variables with the same address:
Person (const string& strName, const string& strJob)
{
szName = new char[strName.size()];
strcpy (szName, strName.c_str());
szJobTitle = new char [strJob.size()]; // this creates memory leak (1)
strcpy (szJobTitle, strJob.c_str());
}
You get a memory leak because you allocate new memory and place it in szJobTitle. &szJobTitle uses the same memory location as &szName, so with the assignment in line (1) you loose the address allocated in szName. If szName and szJobTitle were of different types (with non-matching memory footprints), setting szJobTitle would also corrupt (or only partially overwrite szTitle).
What will be the correct implementation for the destructor?
I think you do not have enough details for implementing the destructor. Look into the concept of discriminated unions in C++ to see how to implement this correctly. Normally your union members should manage their own memory (use std::string, not char*) and then your destructor would only delete what was allocated (but you will have to call it explicitly).
Same way, how to destruct a class object, if my class contains an union member (how to wrtie destructor for class including a Union)?
Again, look at discriminated unions. It is basically the association of a union and an enum, where the enum maps to the members of the union and is set to specify which of the members of the union was set.