I need to insert pointers of classes (inherited from QObject) into a QList. I know that the following syntax can be used:
.h
QList<MyObject*> list;
.cpp
list.append(new MyObject("first", 1));
list.append(new MyObject("second", 2));
...
and then free memory:
if(!list.isEmpty())
{
qDeleteAll(list);
list.clear();
}
This should be valid and does not cause any memory leaks (as far as I know). However, I need to initialize objects before adding them to the collection. Can the following piece of code cause some errors like memory leaks or dangling pointers (I'll use the same way to delete pointers as above)?
MyObject *obj;
for(i = 0; i < 5; i++)
{
obj = new MyObject();
if(!obj.Init(i, map.values(i)))
{
// handle error
}
else
{
list.append(obj);
}
}
Thanks.
if you take care of "obj" (the allocated but not initialized instance) in the "// handle error" case, your code is ok.
Use QSharedPointer instead.
QList<QSharedPointer<MyObject> > list;
To free memory you only have to do
if(!list.isEmpty())
{
list.clear();
}
To append to list
list.append(QSharedPointer<MyObject>(new MyObject("first", 1)));
list.append(QSharedPointer<MyObject>(new MyObject("second", 2)));
Use RAII (Resource Allocation Is Initialization). Initialize the object in constructor directly.
Then the code would look like:
for(i = 0; i < 5; i++)
{
list.append( new MyObject( i, map.values(i)));
// In case of initialization failure, throw exception from the constructor
}
You can use QScopedPointer..
From the Qt 4.6 documentation,
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction.
Managing heap allocated objects manually is hard and error prone, with the common result that code leaks memory and is hard to maintain. QScopedPointer is a small utility class that heavily simplifies this by assigning stack-based memory ownership to heap allocations, more generally called resource acquisition is initialization(RAII).
Hope it helps..
Edit:
For example,
You will use,
QScopedPointer<QWidget> p(new QWidget());
instead of
QWidget *p = new QWidget();
and add the QScopedPointer into your QList without worrying about memory leak and dangling pointers.
Related
This isn't the code I'm working on but it's the gist of what I want to do.
object *objects; int totalObjects;
void addObject(object o)
{
objects[totalObjects] = o;
totalObjects++;
}
It's giving me an access error when I try this:
Unhandled exception at 0x00e8a214 in crow.exe: 0xC0000005: Access violation writing location 0xcccccccc
Am I going to have to use 'new' and if so do I have to create a new array to copy to every time? Can I just add or take elements from the array I'm using?
Why don't you just use std::vector?
std::vector<object> objects;
void addObject(object o)
{
objects.push_back(o);
}
..or
void addObject(const object &o)
{
objects.push_back(o);
}
to remove additional copying.
When it comes to implementing your own dynamic array without std::vector, Yes. you need to allocate new memory, and copy your array to new memory block. Here's my example code with malloc and placement new.
#include <stdlib.h> // for malloc/free
#include <new> // for placement new, std::bad_alloc
object *objects = nullptr;
size_t totalObjects = 0;
void addObject(const object &o)
{
object *old_objects = objects;
size_t old_size = totalObjects;
size_t new_size = totalObjects + 1;
object *new_objects = (object *)malloc(sizeof(object) * new_size);
if (new_objects == nullptr)
throw std::bad_alloc();
size_t i;
try
{
for (i = 0; i < old_size; ++i)
{
new (&new_objects[i]) object(old_objects[i]); // placement new
}
}
catch (...)
{
// destroy new_objects if an exception occurs during creating new_objects
for (size_t j = 0; j < i; ++j)
{
new_objects[i].~object();
}
free(new_objects);
throw;
}
objects = new_objects;
free(old_objects);
}
(I haven't tested the code yet >o<)
Note that I used malloc and placement new, not new operator. It's impossible to call copy constructor of each element of the dynamic array with array-new.
However, if your object is TriviallyCopyable, you can use realloc. It can be more efficient, because realloc can just expand memory block, without copying - if the memory is enough.
..And you can select multiple lines and just press TAB in Visual Studio (..or many other editors).
You declared an object pointer, but not yet allocated the actual memory to store object objects. Your assignment statement merely tries to copy the input object o into an unallocated array member.
This is why you should use new before the assignment. The new operator asks the system to allocate some memory in the required size, then return the address of that memory and assign it to the pointer. Then, the pointer points to that newly allocated memory and the assignment (or copying) can be made.
When you finished using the array space, you should free the allocated memory using delete.
Okay, I'm going to add an answer to my own question. Let me know if this is bad etiquette. I just wanted to post some of my own code to duel with yours.
#include <vector>
std::vector<object> objects;
okay so I want to have two arrays (vectors) for the objects and double for distances so I may end up with
std::vector<double> distances;
void swap(unsigned int a, unsigned int b)
{
objects.swap_ranges(a,b);
distances.swap_ranges(a,b)
}
I'm going by the cplusplus.com reference for this function so let me know if I have it wrong. I'm going to go through it and completely redo my code.
Is there a type like the matrix that will let me hold data of different types so I don't have to invent a new object to handle each one individually?
If what you wrote is the most efficient and fast way to do this then I'll make a new class to hold both items.
thanks :)
I have a problem.
The compiler keeps warning me for invalid use of the constructor.
All i wanted to do is to create a new course in the class. whats wrong?
int StArray::addCS_Course(int id, int CourseNum, char* CourseName,int HwNum, float HwWeigh, bool Takef, char* BookName){
int i;
CS_Course* course;
if ((CourseNum<0)||(HwNum<0)||(HwWeigh<0)||(HwWeigh>1))
return 0;
for (i=0;i<StudentNum_;i++){
if (Arr_[i]->getID()==id) {
course=(CS_Course*)malloc(sizeof(CS_Course*));
if (course==NULL) {
fprintf(stderr,"Malloc failed\n");
exit(0);
}
course->CS_Course::CS_Course(CourseNum,CourseName,HwNum,HwWeigh,Takef, BookName);
if (Arr_[i]->addCS_Course(course)==1)
return 1;
else
{
free(course);
return 0;
}
}
}
return 0;
}
To create a new object in C++, you don't do this:
course = (CS_Course*) malloc(...);
course->CS_Course::CS_Course(...);
you do this:
course = new CS_Course(...);
That code looks after both allocating memory and calling the constructor.
You then delete your object with delete course; rather than free(course);
(But as juanchopanza points out in the comments, it's considered bad form to create objects on the heap in C style like this - you should prefer to use standard library containers and avoid the use of new. That's a whole nother discussion - you might want to read a tutorial on modern C++.)
Edit by #RemyLebeau: If you need to construct an object in existing memory, use placement new instead:
buffer = malloc(...);
course = new (buffer) CS_Course(...);
But then you have to call the destructor manually:
course->~CS_Course();
free(buffer);
malloc(sizeof(CS_Course*)) allocates enough space for a pointer to a CS_Course, not a CS_Course itself. If malloc were the right way to dynamically allocate memory for an object, you would need to call it like this:
malloc(sizeof(CS_Course));
However, malloc isn't the right way to do this; in C++, you use new to dynamically allocate memory for objects:
course = new CS_Course; //Use the default constructor
or
//Use constructor with 2 parameters
course = new CS_Course(constructor_param1, constructor_param2);
Of course, if you don't need a pointer, you can (and should) create a CS_Course object like this (generally referred to as allocating on the stack):
CS_Course course; //default constructor
//constructor with 2 parameters
CS_Course course2(constructor_param1, constructor_param2);
i saw some code like below, but i didn't see any delete statement, is there any memory leak problem?
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
}
If you use vector<RStatus*>, then you have to use delete, otherwise you will have a memory leak.
However, if you use vector<RStatus>, then you don't have to use delete — this is recommended1.
1. If you want to use pointers, then the recommendation is that you should be using smart pointers such as std::unique_ptr, or std::shared_ptr.
Yes, you should free your memory allocated :
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<RStatus*> rsVec;
RStatus* rs = null;
rs = new RStatus(); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs);
// free :
unsigned int size = rsVec.size();
for (unsigned int i = 0; i < size; i++ )
delete rsVec[i]; // delete because you used new
}
If you don't do that, all the memory will never be released at the vector destruction.
I would suggest you to use std::vector<RStatus> instead of std::vector<RStatus*>.
You may also used smart ptr. You can found some documentation about it here : http://www.cplusplus.com/reference/memory/shared_ptr/
EDIT: As suggested in comments, if an exception is thrown at rsVec.push_back(rs), the memory allocated will be lost, that's why smart pointers would be a better solution. Or again, use std::vector<RStatus> instead.
Yes, there is a memory leak: the pointer to the created structure is lost after the vector is destroyed, and the memory is never released.
Unless someone performs a delete for each element of rsVec before clearing or destroying the vector.
Yes, that code leaks the RStatus.
It also does nothing else: possibly the real code's vector gets passed to some function that takes posession of the vector's contents.
Tracking down memory leaks is generally not a local problem: every use of that pointer has to, in theory, be examine to figure out if it leaks. Techniques like 'if I allocate it, delete it' and RAII (including smart pointers) attempt to make it more local, so you can tell from an incomplete program if there is a leak.
use boost::shared_ptr if you don't want to bother yourself with a deletion of allocated objects.
http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm
struct RStatus
{
int fid;
int status;
};
void Foo()
{
vector<shared_ptr<RStatus> > rsVec;
shared_ptr<RStatus> rs = shared_ptr<RStatus>(); // empty shared_ptr
rs.reset(new RStatus()); // memory allocated here!
rs->fid = 0
rs->status = 0;
rsVec.push_back(rs); // shared_ptr is copied
}// vector is destroyed and shared_ptrs also
be careful however not to mixed up things using both shared_ptr and ordinary, raw pointers to avoid situation when shared_ptr tries to delete object which is already deleted
The proxy objects generated by gSoap indicate that I should use a vector of pointers:
class SOAP_CMAC ota__RoomStayTypeRoomRates
{
public:
std::vector<class ota__RoomRateType * >RoomRate;
//....
};
Rather than using:
vector.push_back(new Object());
and then having to delete the objects, I thought I might create a vector of objects and then use the address of those objects as they will be destroyed when the vector goes out of scope, thereby avoiding memory leaks:
OTARoomRates roomRates;
std::vector<ota__RoomRateType> rateObjectList;
rateObjectList.reserve(7);
for (int i = 0; i < 7; i++)
{
rateObjectList[i].RoomTypeCode = &roomTypeCode;
rateObjectList[i].RatePlanID = &ratePlanID;
//...
roomRates.RoomRate.push_back(&rateObjectList[i]);
}
I get a segfault. I suppose it's a bad idea. Can you explain why?
rateObjectList.reserve(7) doesn't actually allocate or construct any ota__RoomRateType objects; it simply requests that the vector expand its capacity enough to hold 7 objects.
Potentially, you wanted rateObjectList.resize(7). Or std::vector<ota__RoomRateType> rateObjectList(7); if you know the number at vector creation time.
Can you explain why?
Sure. If someone holds roomRates when rateObjectList destroyed then any attempt to use a pointer from roomRates can cause SEG_FAULT. That's a bad idea, anyway.
This is better in this case
vector.push_back(new Object());
Even better is to use smart-pointers, like boost::shared_ptr
I've been brushing up on my C++ as of late, and I have a quick question regarding the deletion of new'd memory. As you can see below i have a simple class that holds a list of FileData *. I created an array to hold the FileData objects to be pushed into the list. When ReportData is destructed I loop through the list and delete each element. My question is, how can i delete the array when I'm done using reportData, so that I do not have any memory leaks?
Report.h
class REPORTAPI ReportData {
public:
ReportData()
{
}
virtual ~ReportData()
{
printf("Starting ReportData Delete\n");
for (list<FileData*>::iterator i = ReportFileData.begin(), e = ReportFileData.end(); i != e; )
{
list<FileData*>::iterator tmp(i++);
delete *tmp;
ReportFileData.erase(tmp);
}
for (list<SupressionData*>::iterator i = ReportSupressionData.begin(), e = ReportSupressionData.end(); i != e; )
{
list<SupressionData*>::iterator tmp(i++);
delete *tmp;
ReportSupressionData.erase(tmp);
}
ReportFileData.clear();
ReportSupressionData.clear();
printf("Finished ReportData Delete\n");
}
list<FileData *> ReportFileData;
list<SupressionData *> ReportSupressionData;
}
extern "C" __declspec(dllexport) FileData* __stdcall createFileData(string fileName, long recordCount, long addPageCount)
{
return new FileData(fileName, recordCount, addPageCount);
}
Main.cpp
ReportData *reportData = createrd();
if (reportData != NULL)
{
CreateFileDataFunc createfd (reinterpret_cast<CreateFileDataFunc>(GetProcAddress (dll, "createFileData")));
const int num_files = 5;
FileData *fileData[num_files];
char buff[256] = {'\0'};
for (int i = 0; i < num_files; i++)
{
sprintf(buff, "test: %d", i);
fileData[i] = createfd(buff, 1, 1);
reportData->ReportFileData.push_back(fileData[i]);
}
delete reportData;
reportData = NULL;
delete [] fileData; // this is throwing an access violation error:
//EAccessViolation: 'Access violation at address 326025AF. Write of address 00000008'.
}
--- I removed the delete oprations from the ReportData dtor
and I'm now looping and deleting:
for(int i = 0; i < num_files; i++)
{
delete fileData[i];
}
This is easier to understand then having to rely on a separate object's dtor to clean up memory.
You don't. fileData is an automatic (stack) variable. You didn't allocate it with new, so you don't delete it.
[Edit: also I'm not sure, but I think you could face problems deleting those FileData objects from main.cpp, considering that they were allocated in some dll. Does the dll provide a deleter function?]
Your array is not dynamically allocated, so you don't need to delete it. Each element, however, is pointing to a dynamically allocated object (from your comment):
createfd is a function pointer that returns a new instance of FileData though
What you need to do is loop over the elements of the array, and free each of them.
for(int i = 0; i < num_files; i++)
{
delete fileData[i];
}
// allocate on the stack, no manual delete required
FileData *fileData[num_files];
// allocate on the heap, must delete after usage
FileData *fileData = new FileData[num_files];
// ..
delete [] fileData;
Have you thought about wrapping FileData* with a smart pointer?
The problem with your dtor is that an exception will cause a memory leak (with some other problems relating to exceptions leaking out of dtor's).
"My question is, how can i delete the array when I'm done using reportData, so that I do not have any memory leaks?"
That's the wrong question. The right question is "who should delete these FileData objects?", and the answer is "whoever constructs them, ideally, in this cae Main.cpp". Farming out the job to reportData is awkward and precarious; doing the job twice (once in the ReportData destructor and again in Main.cpp) violates memory.
If you must destroy the objects in ~ReportData(), just don't do anything about them in Main.cpp. Then your code will be correct. Horrible, but correct.
Don't deallocate anything in main().
The destructor for reportData will handle everything allocated with createfd() (just make sure that createfd() is returning what it allocated with new(), since you must not delete anything that was not new'd).
fileData is allocated locally, on the stack, not through new. Since it wasn't allocated by new, don't delete it.
The pointers that were passed into fileData were also passed into reportData, and reportData is responsible for all deletions there. You could check to see that they weren't allocated from an inaccessible memory pool (say in a dynamically linked library); if they were, that's a problem.
So, assuming the deletes are correct in the ReportData destructor, remove any deletion of fileData and you're good.
There is no need to delete or clear either of the two lists - this will be done for you by the default destructor. Assuming that the pointers the lists contain (to "arrays"? I'm not clear) have been dynamically allocated, you need to delete them. However, you can (and should) avoid having to do this explicitly by making the lists contain std::vectors or suitable smart pointers.