Deleting an array of std::string allocated with malloc in C++ - c++

This is a follow up from my question at: Array of strings with malloc on C++
As I have implemented Tony D solution, I have allocated memory for an array of std::string with malloc and then created the std:string for each one of the elements with new according to:
void* TP = malloc(sizeof (string) * SS);
for (int i = 0; i < SS; i++) {
new (&((string*)TP)[i]) std::string(Token[i]);
}
(Token is a vector<string> and SS an int)
I know this is not recommended, I know it is not elegant, I know there
are many other solutions for this array creation and filling, but I need to do
it this way
The issue I encounter now is at the array deletion. As I create each std::string separately but the allocation for the array with a malloc, in my destructor I have written:
for (int i = 0; i < SS; i++) {
delete (&((string*) TP)[i]);
}
free(TP);
But when running, the free(TP) is accusing a "double free or corruption".
By commenting the free(TP) I solve the issue for runtime (hidding the real issue), but I need to be sure all memory is released as this may cause a memory leak within the class.
So, is the deletion of each element of TP enough to free all that memory? From my understanding the malloc has allocated memory independently and it needs to be free independently from the std::string elements; but then, why do I get this error?

You're doing a placement-new to run std::string's constructor on the malloc allocated block, but then you're using delete which will run the destructor AND try to free the memory (you don't want to do the second one here since you're freeing with free()).
You want to run the destructor manually, like this...
for (int i = 0; i < SS; i++) {
(&((string*) TP)[i])->~string();
}
free(TP);

First, let's clean up your code. I suggest you stay away from void* for your array type. Then you can do this, which is a little easier to read, especially on the new() operator:
std::string* TP = (std::string*) malloc(sizeof (std::string) * SS);
for (int i = 0; i < SS; i++) {
new (&TP[i]) std::string(Token[i]);
}
Now, to free the strings, you have to call their destructor directly, don't use delete (there is no placement-delete operator, like you are assuming):
for (int i = 0; i < SS; i++) {
TP[i].~string();
}
free(TP);
Now, with that said, you clearly have access to std::vector, so there is no good reason to use malloc() instead:
std::vector<std::string> TP(SS);
for (int i = 0; i < SS; i++) {
TP[i] = Token[i];
}
Or:
std::vector<std::string> TP;
TP.reserve(SS);
for (int i = 0; i < SS; i++) {
TP.push_back(Token[i]);
}
Or:
std::vector<std::string> TP(Token.begin(), Token.begin()+SS);

Related

How would I de-allocate this?

Just curious as to how I would delete this once it is done being used.
TicTacNode *t[nodenum];
for (int i = 0; i < nodenum; ++i)
{
t[i] = new TicTacNode();
}
Would any pointers that are assigned with values in t need to be deleted as well?? For example,
TicTacNode * m = (t[i + 1]);
Like this:
TicTacNode *t[nodenum] = {};
for (int i = 0; i < nodenum; ++i)
{
t[i] = new TicTacNode();
}
...
for (int i = 0; i < nodenum; ++i)
{
delete t[i];
}
Though, you really should use smart pointers instead, then you don't need to worry about calling delete manually at all:
#include <memory>
std::unique_ptr<TicTacNode> t[nodenum];
for (int i = 0; i < nodenum; ++i)
{
t[i].reset(new TicTacNode);
// or, in C++14 and later:
// t[i] = std::make_unique<TicTacNode>();
}
Or, you could simply not use dynamic allocation at all:
TicTacNode t[nodenum];
Would any pointers that are assigned with values in t need to be deleted as well?
No. However, you have to make sure that you don't use those pointers any more after the memory have been deallocated.
Just curious as to how I would delete this once it is done being used.
As simple as this:
std::unique_ptr<TicTacNode> t[nodenum];
for (int i = 0; i < nodenum; ++i)
{
t[i] = std::make_unique<TicTacNode>();
}
// as soon as scope for t ends all data will be cleaned properly
or even simpler as looks like there is no reason to allocate them dynamically:
TicTacNode t[nodenum]; // default ctor is called for each object and all will be deleted when t destroyed
Actual you don't have to explicitly allocate and deallocate memory. All you need is the right data structure for the job.
In your case either std::vector or std::list might do the job very well
Using std::vector the whole code might be replaced by
auto t = std::vector<TicTacNode>(nodenum)
or using std::list
auto t = std::list<TicTacNode>(nodenum)
Benefits:
Less and clear code.
No need for std::new, since both containers will allocate and
initialise nodenum of objects.
No need for std::delete, since containers will free memory
automatically when they go out of scope.

Locally defined Double array makes the program crash

I have the following variables defined locally in a function member of a class in C++:
double coeff, mincoeff, minratio,
equality[100][5000],
tableau[51][5052],
x[50][100];
When running the program crashes. When I comment out equality array it works but If I do not comment it out, it make the program crashes. It is not true for tableau array and it always works with 'tableau' array and without 'equality' array. I saw a post to use malloc() function to assign space dynamically like :
double *equality;
equality = malloc(500000*sizeof(double));
But it gives me an error of no conversion from void* to double*. Is there another way?
allocate eqaulity on the heap and when you're done with it free memory:
int main()
{
double** equality = new double* [100];
for(int i(0); i < 100; i++)
equality[i] = new double[5000];
for(int i = 0; i < 100; i++)
delete[] equality[i];
delete[] equality;
equality = NULL;
std::cout << std::endl;
return 0;
}
Like #user657267 have mentioned, you are asking 4MB of continuous chunk of memory for equality. Best thing to do here is to ask for the memory dynamically.
double **equality = new (nothrow) double*[100]; //Or do exception check to make sure you have enough memory
if (equality!=nullptr)
{
for(int i(0); i < 100; i++)
{
equality[i] = new (nothrow) double[5000]; //Again or do exception check to handle exception if it cannot get asked memory.
if (equality[i] == nullptr)
{
//Handle the situation where memory could not be allocated
...
}
}
}
else
{
//Handle not being able to allocate memory
}
Regarding c-style malloc (works with C++ as well), you have to cast to correct data type like following:
double *equality;
equality = (double*) malloc(500000*sizeof(double));
Note: do not forget to free what you have allocated.

Allocating Memory with Pointers

I'm new to C++, trying to follow a tutorial series to learn the language, the challenge given for allocating memory is to allocate memory for 26 chars and then fill them with the alphabet, abcde... etc.
I thought I knew the solution but ran into this error:
Invalid address specified to RtlValidateHeap( 00490000, 0049D9EC ) the part that is throwing me off is the program executes fully, a-z but still throws this error
Here is my code:
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; i++, pChar++, c++) {
*pChar = c;
cout << *pChar << flush;
}
delete[] pChar;
Sorry if the question is worded poorly, I am new to both c++ and stackoverflow.
When you say delete[] pChar; you are in fact attempting to delete what pChar is currently pointing at, which is not the same spot as where it was originally allocated.
In short, when you allocate something with new it puts some data about the allocation (size of the allocation for example so you do not need to say delete[26] pChar; like you had to when C++ was new) usually to the left of the newly allocated memory, and it is probably interpreting things you have written (the alphabet) as that information when trying to use it to free the memory, which is of course not going to work.
You should store a copy of the original pointer to the memory you have allocated instead and use that to delete, or perhaps a better option, use i and subscripts to index via pointer arithmetic instead like:
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; i++, c++) {
pChar[i] = c;
cout << pChar[i] << flush;
}
delete[] pChar;
The trouble is that when control leaves the loop, pChar points to a location one past the end of the array. You then call delete[] on that pointer, which is like putting a wrecking ball through the wrong house.
As already mentioned in the other answers, you cannot call delete[] on a pointer you have changed since calling new []. It's undefined behavior.
delete [] needs to get passed the exactly same pointer value as you had achieved when calling new[].
And here's the most simple fix, without need to change pChar:
#include <iostream>
int main()
{
char c = 'a';
char *pChar = new char[26];
for (int i = 0; i < 26; ++i) {
pChar[i] = c; // access the character by index ...
std::cout << pChar[i] << std::flush; // access the character by index ...
// ++pChar; DON'T change the original pointer
++c;
}
delete[] pChar;
return 0;
}
Live Demo

Access Violation Writing to location

Im new to c++ and I dont know what this error means. It reads from a file and tries to store the values in a char * [].
The file contains:
5,Justin,19,123-45-6789,State Farm,9876,Jessica,Broken Hand,
This is my code.
void Hospital::readRecordsFile(){
std::ifstream fileStream;
fileStream.open(fileName); // Opens the file stream to read fileName
char * temp [8];
int i = 0;
while(!fileStream.eof()){
fileStream.get(temp[i],256,',');
i++;
}
i = 0;
for(char * t:temp){
std::cout << t << std::endl;
}
}
The error is at the line fileStream.get(temp[i],256,',');
You define an array of 8 pointers to char, but forget to allocate memory so that the pointers point to a valid chunk of memory:
char * temp [8]; // need then to allocate memory for the pointers
Because of this, in the line
fileStream.get(temp[i],256,',')
you end up using memory that's not yours.
Solution:
for(int i = 0; i<8; i++)
temp[i] = new char[256]; // we allocate 256 bytes for each pointer
Better though, use a std::vector<std::string> instead.
In the code you have right now it looks like you implicitly assume that the file has no more than 8 lines, which I find hard to believe. If your file has more than 8 lines, then you'll end up accessing the array of 8 pointers out of bounds, so you'll get another undefined behaviour (usually a segfault). That's why is much better to use standard STL containers like std::vector, to avoid all these headaches.
In case you MUST use pointers and want a variable number of lines, then you have to use a pointer to pointer,
char** temp;
then allocate memory for an enough pointers-to-char,
temp = new char* [1000]; // we believe we won't have more than 1000 lines
then, for each pointer-to-char, allocate memory
for(int i = 0; i < 1000; ++i)
temp[i] = new char[256];
At the end of the program, you must then delete[] in reverse order
for(int i = 0; i < 1000; ++i)
delete[] temp[i];
delete[] temp;
As you can see, it's getting messy.
You never allocated memory for each pointer in temp.
You probably want something like:
for (unsigned int i = 0u; i < 8; ++i)
{
temp[i] = new char[256];
}
The says that the temp variable points to 8 dynamically allocated byte buffers of 256 bytes each.

Allocate multidimensional array using new

When I allocate multidimensional arrays using new, I am doing it this way:
void manipulateArray(unsigned nrows, unsigned ncols[])
{
typedef Fred* FredPtr;
FredPtr* matrix = new FredPtr[nrows];
for (unsigned i = 0; i < nrows; ++i)
matrix[i] = new Fred[ ncols[i] ];
}
where ncols[] contains the length for each element in matrix, and nrows the number of element in matrix.
If I want to populate matrix, I then have
for (unsigned i = 0; i < nrows; ++i) {
for (unsigned j = 0; j < ncols[i]; ++j) {
someFunction( matrix[i][j] );
But I am reading C++ FAQ, who is telling be to be very careful. I should initialize each row with NULL first. Then, I should trycatch the allocation for rows. I really do not understand why all this. I have always (but I am in the beginning) initialized in C style with the above code.
FAQ wants me to do this
void manipulateArray(unsigned nrows, unsigned ncols[])
{
typedef Fred* FredPtr;
FredPtr* matrix = new FredPtr[nrows];
for (unsigned i = 0; i < nrows; ++i)
matrix[i] = NULL;
try {
for (unsigned i = 0; i < nrows; ++i)
matrix[i] = new Fred[ ncols[i] ];
for (unsigned i = 0; i < nrows; ++i) {
for (unsigned j = 0; j < ncols[i]; ++j) {
someFunction( matrix[i][j] );
}
}
}
catch (...) {
for (unsigned i = nrows; i > 0; --i)
delete[] matrix[i-1];
delete[] matrix;
throw; // Re-throw the current exception
}
}
1/ Is it farfetched or very proper to always initialize so cautiously ?
2/ Are they proceeding this way because they are dealing with non built-in types? Would code be the same (with same level of cautiousness) with double* matrix = new double[nrows]; ?
Thanks
EDIT
Part of the answer is in next item in FAQ
The reason for being this careful is that you'll have memory leaks if any of those allocations fail, or if the Fred constructor throws. If you were to catch the exception higher up the callstack, you have no handles to the memory you allocated, which is a leak.
1) It's correct, but generally if you're going to this much trouble to protect against memory leaks, you'd prefer to use std::vector and std::shared_ptr (and so on) to manage memory for you.
2) It's the same for built-in types, though at least then the only exception that will be thrown is std::bad_alloc if the allocation fails.
I would think that it depends on the target platform and the requirements to your system. If safety is a high priority and / or if you can run out of memory, then no, this is not farfetched. However, if you are not concerned too much with safety and you know that the users of your system will have ample free memory, then I would not do this either.
It does not depend on whether builtin-types are used or not. The FAQ solution is nulling the pointers to the rows so that in the event of an exception, only those rows which have already been created are deleted (and not some random memory location).
That said, I can only second R. Martinho Ferndandes' comment that you should use STL containers for this. Managing your own memory is tedious and dangerous.