I want to allocate memory for a huge bulk of objects. Then construct them one by one. So I do the following:
BaseClass* buf = static_cast<BaseClass*> (::operator new (sizeof(BaseClass[5])));
for (int var = 0; var < 5; ++var) {
new (&buf[var]) BaseClass(var);
}
And everything seems ok. But when I add delete:
BaseClass* buf = static_cast<BaseClass*> (::operator new (sizeof(BaseClass[5])));
for (int var = 0; var < 5; ++var) {
new (&buf[var]) BaseClass(var);
// ... do something
delete &buf[var];
}
I got "segmentation fault" error. On second iteration (on constructor).
At the same time
delete [] buf;
works fine.
So the question is - why this?
First of all if you use a placement new then you will need to call destructor explicitly
buf[var].~BaseClass();
Then you can delete just things that have been allocated with a new, while &buf[0] works since it's the address returned by the placement new, &buf[1] has not been directly allocated by the memory manager through ::operator new. You can't free them one by one.
So you should do something like
::operator delete(buf);
Placement new doesn't allocate memory, it just calls the constructor for the memory location you gave it. So you don't need to delete the individual items. Instead of
delete &buf[var];
Try this, which calls the destructor without freeing memory:
buf[var].~BaseClass();
Note that you still need to use ::operator delete on the whole chunk of memory, just not on the individual objects.
You're using delete without a corresponding new. Using placement new to construct objects in previously allocated memory does not require a paired use of the delete operator. Instead placement new should be paired with explicit destructor calls. Since you're calling the global operator new function directly, you should be pairing that with a direct call to the global operator delete function, rather than using the delete operator at all.
However none if this is necessary for what you've described. The following is much easier:
std::vector<BaseClass> buf;
buf.reserve(5);
for (int var = 0; var < 5; ++var) {
buf.emplace_back(var);
}
After you have this collection of objects you can put pointers to them into a std::vector<BaseClass*>:
std::vector<BaseClass*> buf2;
buf2.reserve(buf.size());
std::transform(std::begin(buf), std::end(buf), std::back_inserter(buf2),
std::addressof<BaseClass>);
Just be sure not to do anything to the original vector that invalidates the pointers. You can move it, but don't copy it and then destroy the original.
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 searched the internet for hours and hours and came up with these steps to prevent memory leaks (w/o use of smart pointers and advance tools as such). Please let me know if there are any issues with any of the below findings... Thanks in advance.
for each new there should be a delete.
if the new is inside a class putting the delete in the destructor would take care of the dynamically allocated memory.
if you do a new object obj from class foo in main then in you would have to explicitly delete obj.
if you have multi-dimentional dynamic arrays you have to delete both levels. (I am a bit unsure of this being safe... I thought just one delete for the ptr might do it but after thinking harder I figured it is a dynamic array of dynamic arrays and should treat each as a dynamic array separately).
ex 1.
char *ptr;
ptr = new char[size];
// Some Code here
delete ptr;
ex 2.
//foo.h
class foo {
private:
char * ptr;
public
foo();
~foo();
};
// foo.cpp
foo::foo()
{
ptr = new char[100];
for (int i = 0; i < 100; i++)
ptr[i] = i;
}
foo::~foo()
{
delete ptr;
}
ex 3.
//main.cpp foo class stays the same as ex 2.
int main()
{
foo obj = new foo();
// Some code here
delete obj;
return 0;
}
ex 4.
//foo.h
class foo {
private:
char ** ptr;
public
foo();
~foo();
};
//foo.cpp
foo::foo()
{
ptr = new char[100];
for (int i = 0; i < 100; i++)
ptr[i] = new char[100];
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++)
ptr[i][j] = i;
}
foo::~foo()
{
for (int i = 0; i < 100; i++)
delete ptr[i];
delete ptr;
}
Below are some tips you need to take care while managing memory on your own:-
First and most important of all is:-
1) Always use delete with new and delete[] with new[].Mixing these would result in undefined behavior.
2) Never combine malloc/delete OR new/free.
For your question "if you have multi-dimentional dynamic arrays you have to delete both levels."
Yes you have to take care of them.
Things you mentioned are correct i.e you have to explicitly delete the memory whenever you are allocating memory in heap. Though you missed one important aspect which revolves around RAII. Let's say there's a function in which you are taking care of allocation/deallocation.
void fun ()
{
1) int* ptr;
2) ptr = new int; //allocated memory.
3) ... //do something with ptr.
4) delete ptr; //done with ptr now delete it.
}
Now you are doing good by deleting memory which you allocated using new. However, there could be a chance that program execution won't even reach to your delete. ( in case exception is thrown in STEP#3). That case would constitute a memory leak.
To care of these issues we have smart pointers based on the concept of RAII. They will automatically delete the memory they are referring to whenever go out of scope that means you don't need to take care of memory management.
for each new there should be a delete.
Yes. And to be more precise: Every new must have a matching delete, and every new[] must have a matching delete[]
if the new is inside a class putting the delete in the destructor would take care of the dynamically allocated memory.
No! You also should take care on what should happen for copies through copy constructor or assignment, unless you explicitly forbid these operations. See What is The Rule of Three? for more details.
if you do a new object obj from class foo in main then in you would have to explicitly delete obj.
?? See 1.?
if you have multi-dimentional dynamic arrays you have to delete both levels. (I am a bit unsure of this being safe... I thought just one delete for the ptr might do it but after thinking harder I figured it is a dynamic array of dynamic arrays and should treat each as a dynamic array separately).
Yes, you always have to take care about proper memory management, if you're using raw pointers, no matter how many levels of indirection.
My final advice is, leave your head clean about bothering with such questions, but use the stuff provided with the <memory> smart pointers, and standard c++ containers.
Don't use new/delete directly, unless you're a 100% sure what you're doing, and you're a 200% sure you really need to do it.
As you're asking about actual issues:
(ex 2.) The delete doesn't match the new char[]
ptr = new char[100];
// ^^^^^
foo::~foo() {
delete [] ptr;
// ^^ put the square brackets there
}
same for (ex 4.)
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);
Lets say i have a class like this:
class LolClass {
LPWSTR* stuff;
LolClass::LolClass(LPWCHAR lols) {
stuff = new LPWSTR[100];
for (int i = 0; i < 100; i++) {
stuff[i] = new wchar_t[wcslen(lols)+1];
wcsncpy(stuffs[i], lols, wcslen(lols)+1);
}
}
LolClass::~LolClass() {
delete[] stuff;
}
}
so if i call
LolClass* veryfunny = new LolClass(L"lol!");
it would make me 100 lol's, problem is when i call
delete veryfunny;
it deletes the pointer array but not the individual wchar_t's, if i try and loop through the wchar_t's and delete them then i just crash and i dont know what to do since i know for fact that they are still there even after i delete veryfunny (i checked by passing one of the pointers outside the class)
Thanks!
If you call
LolClass* veryfunny = new LolClass(L"lol!");
then you will eventually need to call:
delete veryfunny;
But for arrays, you need delete[]: stuff[i] = new wchar_t[n]; delete [] stuff[i];
In your code, you need to first loop over stuff and delete[] the elements, and then delete[] the array stuff itself.
Or just use a std::vector<std::wstring>.
Update: From what I understand, you're not actually worried about deleting *veryfunny, but rather about how to write a correct destructor for LolClass. Note that the destructor also gets invoked for global and automatic objects, e.g. { LolClass x(L"hello"); } /* boom */, so it doesn't really matter how you instantiate an object for LolClass. You have to get the class right in any case.
David Schwartz wins after all, the wchar's didnt let themselves be deleted because they werent null terminated
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.