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.
Related
When I create a class, include a pointer in it, and create an object in automatic storage, should I include a destructor in the class? (is it necessary to free the space in the memory?)
Example:
class Node{
char *Name;
int age;
Node(char *n = 0, int a = 0) {
name = strdup(n);
age = a;
}
~Node(){
if (name != 0)
delete(name);
}
}
Node node1("Roger",20);
is it necessary to free the space in the memory?
Yes, it's essential to avoid memory leaks.
Anyway you must use free(name); in your example, since strdup() is a pure C function, and uses the malloc() function to allocate the memory for the copy returned.
Also, you should avoid managing raw pointers yourself in C++. Either use smart pointers, or standard C++ containers, or for your specific case simply std::string.
Raw pointers don't go well with, respectively complicate, implementing the Rule of Three (5/zero).
If you have something allocated from a C-style interface, you can always use a smart pointer, and provide a custom deleter function, that actually uses the appropriate free() call.
If your class has a pointer that points to memory that is allocated with new \ new[] \ malloc() then you need to implement the Rule of Three
That said, instead of using a raw char * and manual memory management, use a std::string instead. you can still get a const char* out of it if you need it for other functions but it fully self managed container. With it you would not need to provide a copy constructor or destructor as the default ones provided by the compiler will work.
Yes, this is mandatory to avoid memory leaks. It doesn't matter if you are using a class or something else. It's important what strdup says. But you must not use delete, instead use free. The memory in strdup is created by using malloc, not new.
http://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html
strdup - duplicate a string
The returned pointer can be passed to free(). A null pointer is
returned if the new string cannot be created.
P.S. Don't miss const in your declaration of char *n, otherwise the caller might expect the string is modified and a simple-string literal cannot be passed without a warning.
P.S.2: Prefer using nullptr instead of 0. This has been discussed several times on SO.
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...
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 ?
I have a fairly simple question that I cannot seem to find an answer for relating to C++ std::string and how it is instantiated with new. Now, I am well aware that any pointer returned from new should be subsequently deleted to prevent memory leak. My question comes from what happens when an existing pointer is subsequently used to instantiate a new string object. Please consider the following simplified example:
char* foo() {
char* ptr;
ptr = new char[ARBITRARY_VALUE];
...
ptr = strncpy("some null terminated string", ARBITRARY_VALUE)
...
return ptr;
}
int main() {
char* buf;
std::string myStr;
buf = foo();
myStr = new std::string(buf);
...do stuff
delete myStr;
delete buf; //Is this necessary?
return 0;
}
My question is simple: does deleting myStr also free the underlying memory used by buf or does buf need to be freed manually as well? If buf has to be freed manually, what happens in the case of anonymous parameters? As in:
myStr = new std::string(foo());
My suspicion is that the underlying implementation of std::string only maintains a pointer to the character buffer and, upon destruction, frees that pointer but I am not certain and my C++ is rusty at best.
Bonus question: How would this change if the class in question were something other than std::string? I assume that for any user created class, an explicit destructor must be provided by the implementer but what about the various other standard classes? Is it safe to assume that deletion of the parent object will always be sufficient to fully destruct an object (I try to pick my words carefully here; I know there are cases where it is desirable to not free the memory pointed to by an object, but that is beyond the scope of this question)?
std::string may be initialized from a C style null-terminated string (const char *). There is no way for std::string to know if you need that const char * free()d, delete[]()d or neither, and as already stated it won't.
Use smart-pointers to automatically delete dynamically allocated objects. There are a few different of these, each specialized for particular purposes. Have a look at scoped_ptr, auto_ptr and shared_ptr. Your project will probably have constraints on which smart pointers you get to use.
In the context of C++ there is never a reason to hold strings in manually declared char arrays, std::string is much safer to use.
I'm working with std::list<std::string> in my current project. But there is a memory leak somewhere connected with this. So I've tested the problematic code separately:
#include <iostream>
#include <string>
#include <list>
class Line {
public:
Line();
~Line();
std::string* mString;
};
Line::Line() {
mString = new std::string("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
}
Line::~Line() {
//mString->clear(); // should not be neccessary
delete mString;
}
int main(int argc, char** argv)
{
// no memory leak
while (1==1) {
std::string *test = new std::string("XXXXXXXXXXXXXXXXXXXXXXXX");
delete test;
}
// LEAK!
// This causes a memory overflow, because the string thats added
// to the list is not deleted when the list is deleted.
while (1==1) {
std::list<std::string> *sl = new std::list<std::string>;
std::string *s = new std::string("XXXXXXXXXXXXXXXXXXXXXXX");
sl->push_back(*s);
//sl->pop_back(); //doesn't delete the string?- just the pointer
delete sl;
}
// LEAK!
// Here the string IS deleted, but the memory does still fill up
// but slower
while (1==1) {
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
}
return 0;
// this does not cause any noticable memory leak
while (1==1) {
std::list<int> *sl = new std::list<int>;
int i = 0xFFFF;
sl->push_back(i);
sl->clear();
delete sl;
}
return 0;
// This does not cause any overflow or leak
while (1==1) {
int *i;
i= new int [9999];
delete[] i;
}
}
Why does my string list cause a memory leak? Shouldn't deleting the list cause the destructors to be called on each contained string?
In the first case, the list class has no idea you allocated the string with new, and cannot delete it. In particular, the list only ever contains a copy of the string that you passed in.
Similarly, in the second case, you never free the line object s, and thus you leak memory. The reason why the internal string is deleted is because you have not correctly implemented a copy constructor. Thus, if you make a copy of a Line object, both of them will reference the same string pointer, and if you try to delete both of them, you are in trouble.
Your Line class needs a copy-ctor and an assignment operator that properly deal with the string pointer.
Alternatively, just have a std::string member rather than a pointer and let the string class handle the memory (that's what it's for).
Here's your leak:
while (1==1) {
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
}
STL collections store elements by value, allocating and releasing space for it. What you allocated you have to release explicitly. Just add delete s to the end of the loop.
If you have to store pointers, consider storing managed pointers like boost::shared_ptr, or look into Boost pointer container library.
On the second look, you don't need to allocate Line on the heap at all. Just change it to:
sl->push_back(Line());
And, as others noted, make sure Line's pointer members are properly managed in copy-constructor, copy-assignment, and destructor.
std::list<Line> *sl = new std::list<Line>;
Line *s = new Line();
sl->push_back(*s);
//sl->pop_back(); //does delete the Line-Element
sl->clear();
delete sl;
You forgot to delete s . You new'ed it, you have to delete it. As you're copying objects around(By stuffing them in a list) while managing memory in your Line class, you also have to provide a copy constructor and assignment operator for your Line class.
Others have addressed specifically why you have your leak - deleting a list of pointers does not delete the objects that are pointed to, and should not as a simple pointer gives no indication whether it was the only reference to that object ), but there are more ways than having to make sure you iterate the list on deletion to delete the pointers.
As far as the example here shows theres no reason to use pointers to anything at all, since you're using them when they enter the scope and discarding them when they leave the scope - simply create everything on the stack instead and the compiler will properly dispose of everything on exiting the scopes. Eg.
while (1==1) {
std::list<std::string> sl;
std::string s = std::string("XXXXXXXXXXXXXXXXXXXXXXX");
sl.push_back(s);
}
If you do need the pointer behaviour (to avoid having to duplicate objects that are linked to by many things etc. etc.) you should take a look at smart pointers, as these will remove many of the pitfalls as they can automatically handle the reference counting and semantics you require. (Specifically take a look at the boost smart pointers)
There are many types of smart pointer you can use depending on specific need and ownership semantic to represent.
The std::auto_ptr has strict ownership - if the pointer is "copied" the original is nulled and ownership transfered - there is only ever be one valid auto_ptr to the object. The object pointed to is deleted whenever the smart pointer with ownership goes out of scope.
Theres also boost shared pointers and weak pointers using reference counting to know when to free the object being pointed to. With Shared pointers each copy of the pointer increases a reference count, and the object pointed to is deleted whenever all the shared pointers go out of scope. A weak pointer points to an object managed by a shared pointer but does not increase the reference count, if all the parent shared pointers are deleted attempting to dereference a weak pointer will throw an easily catchable exception.
Obviously theres a lot more to the range of smart pointers, but I highly suggest taking a look at them as a solution to help with managing your memory.