Using delete inside function - c++

I have problem with calling delete inside functions. When I allocate memory using new inside function it seem do work, but deleting formerly allocated memory causes throwing of std::bad_alloc. Is it even possible, or can I only free memory under "a" from inside of main?
#include <iostream>
using namespace std;
int size = 5;
void alloc (int* t, char**& a) {
t = new int [size];
a = new char* [size];
for (int i = 0; i < size; ++i)
a[i] = new char [size];
cout << "allocated\n";
}
void realloc (char**& a) {
for(int i = 0; i < size; ++i)
delete [] a[i];
delete [] a;
cout << "deleted\n";
a = new char* [size];
for (int i = 0; i < size+5; ++i)
a[i] = new char [size+5];
cout << "allocated\n";
}
void fillArray (char** a) {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
a[i][j] = '.';
}
}
}
void printArray (char** a) {
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
cout << a[i][j];
}
cout << endl;
}
}
int main() {
int* t;
char** a;
alloc(t, a);
fillArray(a);
printArray(a);
size+=5;
realloc(a);
fillArray(a);
printArray(a);
}

You can call delete[] from anywhere. Your problems are much more prosaic. You just have a defect in your code.
You allocate an array of length size. Then you increment size. Then you do this:
for(int i = 0; i < size; ++i)
delete [] a[i];
And because you incremented size already, your loop runs off the end of a. You need to use the same value for size as was used when you allocated the array.
To be quite clear, the following is the flow of execution:
size is assigned to the value 5.
a is allocated with length 5.
size is incremented to the value 10.
You run a for loop from 0 to size-1, that is 0 to 9, and call delete[] a[i].
Clearly the iterations 5 to 9 inclusive are accessing elements of a that were not allocated. And that's undefined behaviour, and so on.
You could fix this by passing the new size to the realloc function as a parameter. Something like this:
void realloc (char**& a, size_t newsize) {
for(int i = 0; i < size; ++i)
delete [] a[i];
delete [] a;
size = newsize;
a = new char* [size];
for (int i = 0; i < size; ++i)
a[i] = new char [size];
}
Obviously you would not modify size outside of this function. You would call the function like this:
realloc(a, size+5);
Taking it a bit further, you might choose to handle the allocations like this:
size_t size = 5;
void alloc(char**& a, size_t newsize) {
size = newsize;
a = new char*[size];
for (int i = 0; i < size; ++i)
a[i] = new char[size];
}
void realloc(char**& a, size_t newsize) {
for(int i = 0; i < size; ++i)
delete[] a[i];
delete[] a;
alloc(a, size+5);
}
All that said, and being perfectly frank, your entire program is a disaster in the making. There are many other errors that I've not covered in this answer. Use standard containers like std::vector and std::string. The standard containers will handle the details of memory allocation, and will do it correctly.

Related

Why not array deallocate when using assignment operator?

When running the code I keep getting error "free(): double free detected in tcache 2". How can I not deallocate new instance array? Shouldn't it be deallocate at the moment I run the second instance? Why deallocate constructor doesn't work for the n instance? How can I solve this? Should I deallocate the arr of n manually in assignment operator?
#include <iostream>
#include <iomanip>
using namespace std;
class spMatrix{
private:
int N;
public:
double** arr;
spMatrix(): N(0), arr(NULL){};
spMatrix(int size): N(size){
N = size;
arr = new double* [size];
for(int i = 0; i < size; i++) arr[i] = new double [size];
};
//copy constructor
spMatrix(const spMatrix& original){
N = original.N;
arr = new double* [N];
for (int i = 0; i < N; ++i)
{
arr[i] = new double [N];
for (int j = 0; j < N; ++j)
{
arr[i][j] = original.arr[i][j];
}
}
}
~spMatrix(){
if(arr != NULL){
for (int i = 0; i < N; i++)
{
if (arr[i] != NULL) delete [] arr[i];
}
delete [] arr;
}
}
spMatrix& operator = (spMatrix const & other){
N = other.N;
arr = other.arr;
for(int i = 0; i < N; i++) {
arr[i] = other.arr[i];
for (int j = 0; j < N; j++){
arr[i][j] = other.arr[i][j];
}
}
return *this;
}
void show(){
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
}
};
int main(int argc, char const *argv[])
{
spMatrix m(2);
spMatrix n(2);
m = n;
m.show();
return 0;
}
In your copy constructor:
N = other.N;
arr = other.arr;
for(int i = 0; i < N; i++) {
arr[i] = other.arr[i];
for (int j = 0; j < N + 1; j++){
arr[i][j] = other.arr[i][j];
}
}
return *this;
}
This only copies/duplicates the 2nd dimension of the 2D-matrix. The first dimension is not duplicated. Try to focus your attention on just the following line:
arr = other.arr;
If you think about this for a moment, it should be clear that you end up with two different objects having the same identical arr class member pointer. This is not correct. Different matrix objects should always be completely independent of each other and not share any pointers in common (at least not without reference-counting, and other complicated semantics).
You simply need to make a copy of arr, too. Everything else remains the same. It should probably be something like:
arr = new double* [N];
Looks like everything else can remain the same, note how this is identical to the same allocation in the regular constructor.
However the assignment operator has the same defect, but after understanding the problem in the copy constructor it should be clear how to fix it (same fix).
Your assignment operator also has a separate bug: it leaks memory. It needs to delete the entire 2D matrix in this, before cloning it from other.
Your problem is in the copy assignment operator:
spMatrix& operator = (spMatrix const & other){
N = other.N; // <<<A>>>
arr = other.arr; // <<<B>>>
for(int i = 0; i < N; i++) {
arr[i] = other.arr[i];
for (int j = 0; j < N + 1; j++){
arr[i][j] = other.arr[i][j];
}
}
return *this;
}
There are two significant and separate problems here. First, the current object owns some memory, an array of N arrays of length N.
However, after line <<>> you no longer know how many arrays you hold.
Second, after line <<>> you no longer know the address of your arrays, and so they are leaked.
Worse, line <<>> is also now pointing this object's array into other's memory, and both objects think they own that array. When one spMatrix destructor runs, the other will still point to it and use deleted memory. When the second one is destroyed, it'll be the second delete on the already deleted memory.
All of the copying you're trying to do in those for loops is not really doing anything, since you're assigning from and to the same address.
You must allocate new buffers before copying them, and not look at the address the other object has... because it's their memory not yours to take.
And you should keep the old pointers around, so that you can delete them after the allocations complete. That way if something fails you can still put it back, without messing your object up first. For example, the logic of line <<>> should be last, not first, only after everything succeeds.
I changed the assignment operator as below and it solved it.
spMatrix& operator = (spMatrix const & other){
N = other.N;
arr = new double* [N];
for(int i = 0; i < N; i++) {
arr[i] = new double[N];
for (int j = 0; j < N; j++){
arr[i][j] = other.arr[i][j];
}
}
return *this;
}

How to create a 2D array using a function?

I am trying to define a 2D array, but I want to do it in a function,
here is my code:
int** createArray( int columns, int rows)
{
int** array[rows];
for(int i = 0; i < rows; i++)
{
array[i] = new int*[columns];
}
for(int i = 0; i <columns; i++)
{
for(int j = 0; j < rows; j++)
{
array[i][j] = 0;
std::cout <<array[i][j];
}
std::cout<<"\n";
}
return *array;
}
int main()
{
int **myArray = createArray(3,5);
for(int k =0; k < 5; k++)
{
if( (myArray[0][k] == 0) && (&myArray[1][k] == 0)) //segmentation fault
{
myArray[2][k] = 10; //segmentation fault
}
delete[] myArray;
}
But it causes errors which can be seen as comments in lines. I am new to C++ and I do not know how to fix this.
Thank you very much
Prefer std::vector over manual memory management:
std::vector<std::vector<int>> createArray(int columns, int rows)
{
return std::vector<std::vector<int>(rows, std::vector<int>(columns));
}
int main()
{
int COLUMNS = 5;
int ROWS = 3;
auto myArray= createArray(COLUMNS, ROWS);
/*
Do stuff
*/
//std::vector handles delete on it's own, no need to clean up
}
If you cannot use std::vector for some reason, this is the a way to initialize 2D array on the heap:
int** createArray(int columns, int rows)
{
int** arr = new int*[rows];
for(int i = 0; i < rows; ++i)
{
arr[i] = new int[columns];
}
return arr;
}
int main()
{
int COLUMNS = 5;
int ROWS = 3;
int** myArray= createArray(COLUMNS, ROWS);
/*
Do stuff
*/
//you need to a delete for every new and delete[] for every new[]
for(int i = 0; i < rows; ++i)
{
delete[] myArray[i];
}
delete[] myArray;
}

Valgrind memory leak pointer

I have this function in order to expand the size of my char **array that I use in two other functions, which is why I'm passing it in by reference. I know I'm supposed to delete array at some point because it's dynamically allocated in this function, but I cant delete it until after I'm done using it in my code. However, valgrind still says memory is definitely lost in the line which contains array = new char *[cap2]. How should I go about deleting this?
void expand(int &size2, int &cap2, char **&array){
int i;
if(size2 ==1)
{
cap2 = size2;
cap2 = cap2*2;
array = new char*[cap2];
for(int n=0; n<cap2; n++)
{
array[n] = '\0';
}
}
else{
cap2 = cap2 *2;
char **temp;
temp = array;
array = new char*[cap2];
for(i =0; i<size2 ; ++i)
{
array[i] = temp[i];
}
for(int k = size2; k<cap2; k++)
{
array[k] = '\0';
}
}
return;
}

Addresses of dynamically allocated arrays spoil depending on the way the array is declared?

The following code seems to work when the array is declared like
int numbers[3]
But when I try declaring it like
int* numbers = new int[3];
After resizing the resized array's first two numbers seem to get lost.
I can't really figure out what is the difference betwean the two declarations. Any clarification will be helpfull.
int main() {
int numbers_size = 0;
int numbers_capacity = 3;
//works when declared like this
//does not work when declared like int* numbers = new int[3]
int numbers[3];
do {
...
if(numbers_capacity == numbers_size)
numbers_capacity = resize_array(numbers, numbers_size);
}while(numbers[numbers_size - 1] != 0);
return 0;
}
int resize_array(int* arr, int arr_size) {
int* temp = new int[arr_size];
for(int i = 0; i < arr_size; i++)
temp[i] = arr[i];
delete [] arr;
arr = new int[4*arr_size];
for(int i = 0; i < arr_size; i++) {
arr[i] = temp[i];
}
delete [] temp;
return 4*arr_size;
}
You are changing the value of arr in resize_array to point to new memory location but the calling function still has the old, now dangling, memory location.
Change the function to:
int* resize_array(int* arr, int arr_size)
{
int* temp = new int[arr_size];
for(int i = 0; i < arr_size; i++)
temp[i] = arr[i];
delete [] arr; // This makes pointer in the calling function
// point to deleted memory.
arr = new int[4*arr_size];
for(int i = 0; i < arr_size; i++) {
arr[i] = temp[i];
}
delete [] temp;
// Return the newly allocated memory.
return arr;
}
and use it like:
numbers_capacity = numbers_size*4; // This is bad. It assumes that
// that you are increasing the size by 4 times.
numbers = resize_array(numbers, numbers_size);
You can simply use a std::vector<int> and avoid all the headache.

creating 2-d array of objects with a constructor with a parameter

I'm trying to create a 2-d array of objects. I'm trying to set the constructor of the class I made equal to a constructor that will take in a parameter. However, I keep getting an error saying:
main.cpp:18:37: error: invalid user-defined conversion from 'test*' to 'const test&'
int main()
{
test arr[9][9];
char s[9][9];
int integerArray[9][9];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
arr[9][9] = new test(s[i][j]);
}
}
return 0;
}
With test being the class. Can anyone help me figure out this error? I understand that the new function returns a void pointer but how can I get it so that my 2d array takes in the parameter?
Thanks.
Your 2d array is not an array of pointers to a test object.
Memory is allocated for your 2d array anyway. So no need for the loop.
Unless you change your declaration
test arr[9][9];
to something like:
test*** arr = new (test**)[rows];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
arr[i][j] = new test(s[i][j]);
}
}
When you declare the array as test arr[9][9];
then the memory is allocated and default constructor is called for each member. So you don't need call new to allocate new memory.
I assume that you goal is to have array of test objects constructed with the value read from std::cin.
Then you have several options:
Easiest solution is to use 2D array of pointers:
It would look like:
test* arr[9][9];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
arr[i][j] = new test(s[i][j]);
}
}
If you want to keep the array of plain test objects (without pointers), the use can either:
Provide a test::set(int) method to set the value after is was constructed.
test arr[9][9];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
arr[i][j].set(s[i][j]);
}
}
Construct temporarily object and then assign it to your already allocated one in the array using operator=(const test&) (or operator=(test &&) in c++11). Note that there's no new here:
test arr[9][9];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
arr[i][j] = test(s[i][j]);
}
}
Or use placement new (this constructs new object in the pre-allocated memory block):
test arr[9][9];
for(unsigned int i = 0; i < 9; i++)
{
for(unsigned int j = 0; j < 9; j++)
{
cin >> s[i][j];
new(&arr[i][j]) test(s[i][j]);
}
}
And last one: If you don't have specific reason to use static 2D array, go for some STL container.
//Class with one arg constructor/no default constructor whose 2d array need to be
// allocated on heap using new
class A
{
public:
A(int i):m_i(i)
{
cout<<"constructor called i="<<i<<endl;
}
~A()
{
cout<<"destructor called i="<<m_i<<endl;
}
int get()
{
return m_i;
}
friend ostream& operator<<(ostream& os, const A& obj);
private:
int m_i;
};
ostream& operator<<(ostream& os, const A& obj)
{
os<<obj.m_i;
return os;
}
typedef unsigned char Byte;
int main()
{
int m=4;
int n=3;
int s[4][3] = { {1,2,3},
{4,5,6},
{7,8,9},
{10,11,12}
};
//Allocate a buffer to hold the array, on heap
Byte* pBuff = new Byte[sizeof(A)*m*n];
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
A* p = new (pBuff+sizeof(A)*(n*i+j)) A(s[i][j]);
}
}
//Accessing array
A (*testArr)[3] = (A (*)[3])pBuff;
for(int i=0;i<4;++i)
{
for(int j=0;j<3;++j)
{
cout<<"testArr["<<i<<"]["<<j<<"]="<<testArr[i][j]<<endl;
}
}
//after you are done with the array of objects.
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
A* p=(A*)(pBuff+sizeof(A)*(i*n+j));
p->~A(); //call destructor for each object.
}
}
delete[] pBuff; //Delete the buffer.
return 0;
}
Within you code you basically have a type mismatch, since you try to assign a pointer to X to an X.
I assume this happens, because you try to assign a test, but test has no default constructor.
An easier solution, that avoids a default constructor, but has some overhead with copy construction, would be to use a vector with a given constructor.
std::vector<std::vector<test, test(char(0))> > arr;
char a(0);
for (unsigned int i = 0; i < 9; ++i) {
for (unsigned int j = 0; j < 9; ++j) {
std::cin >> a;
arr[i][j] = test(a);
}
}