I'm new to pointers and dynamic memory. The program is supposed to be an array-based stack.
I need help with an error that occurs when I try to allocate memory to the pointer variable _pArr in the .h-file. When I try to create a new array with new double[] I get an 'unreadable memory' error message when I debug the code.
In the code down below I have created a new array in the .cpp-file and then copy it to the _pArr pointer, but I still get the same error.
class CStack{
public:
Stack(void);
~Stack(void);
.
.
.
private:
int _capacity=NULL;
int _size=0;
double* _pArr;
}
CStack::CStack(void)
{
if (_capacity == 0){
_capacity = 10;
}
else{
_capacity = _capacity * 2;
}
double* arr;
arr = new double [_capacity]
_pArr=arr;
delete[] arr;
}
Why does this error occur and how can I fix it?
Here's what your code is doing in the constructor:
// Allocate memory for an array and set arr to point to that array.
double* arr;
arr = new double [_capacity]
// Set _pArr to point to the same array.
_pArr=arr;
// Delete the array that arr and _pArr point to. If you
// deference _pArr after this, bad things will happen.
delete[] arr;
So you shouldn't be deleting the array immediately after you allocated it. (There's also a missing semicolon there.) Getting rid of that will likely fix your problem, but then you then need to delete the array in the class's destructor. And if you must use new[]/delete[], it would be far easier to do it in a single step, rather than creating a useless temporary variable:
CStack::CStack(void)
{
if (_capacity == 0){
_capacity = 10;
}
else{
_capacity = _capacity * 2;
}
_pArr = new double [_capacity];
}
CStack::~CStack(void)
{
delete[] _pArr;
}
Unrelated to your question, but that code that doubles _capacity doesn't do anything useful, as capacity will always be zero when the constructor is called. If you intended for this to expand an existing CStack, then you will need to put it in a method, and will need to worry about creating a new array for the stack, copying the contents of the old one into the new, and then deleting the old one.
Related
I have created an array pointer as a global variable like this:
T *bag;
bag = new T[size];
I have a method where I insert things into the array; however, if it detects that it will overflow the array, I need to resize the array (without vectors). I've been reading about this question all over stack overflow but the answers don't seem to apply to me because I need the data from the old array copied into the new array. Additionally, if I create a new array of a larger size inside the method and then copy the data over to the new array, once the method ends, the array will disappear, but I need it to be a global variable again so all my methods can see it...How should I proceed?
Thank you
Memory, allocated by new, would not disappear after your method ends.
You can return pointer to a new array by usung reference: void f(int *&ptr, size_t &size).
Also, be aware, that you need to clear memory manually arter you use it. For example:
int* newArray = new int[newSize];
... copying from old array ...
int* temp = oldArray;
oldArray = newArray;
delete[] temp;
To resize an array you have to allocate a new array and copy the old elements to the new array, then delete the old array.
T * p_bag;
p_bag = new T[old_size];
//...
T * p_expanded_bag = new T[new_size];
for (unsigned int i = 0; i < old_size; ++i)
{
p_expanded_bag[i] = p_bag[i];
}
delete[] p_bag;
p_bag = p_expanded_bag;
You could use std::copy instead of the for loop.
The thing you need can do the following things
Automatically handle the resizing when requested size is larger than current array size.
When resizing, they can copy the original content to the new space, then drop the old allocation immediately .
There is a non-global-variable way mechanism they can track the array pointer and the current size.
The thing is very similar to std::vector. If it is not allowed to use, you may need manage a dynamic allocated resource like std::vector on your own. You can reference the implementation in that answer link.
If eventually you need to wrap it in a class, make sure to follow the big 3 rules (5 rules in C++11)
You can use realloc from c if you have array of chars/ints/doubles... or some other fundamental data type or classes with only those variables (eg. array of strings won't work).
http://www.cplusplus.com/reference/cstdlib/realloc/
bag = (T*) realloc(bag, new_size * sizeof(T));
Realloc automatically allocate space for your new array (maybe into the same place in memory) and copy all data from given array.
"The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location."
Example:
#include <stdio.h> /* printf*/
#include <stdlib.h> /* realloc, free */
#include <iostream>
int main()
{
int old_size = 5;
int new_size = 10;
int *array = new int[old_size];
printf("Old array\n");
for (int i=0; i<old_size; i++) {
array[i] = i;
printf("%d ", array[i]);
}
printf("\nArray address: %d\n", array);
array = (int*) realloc(array, new_size * sizeof(int));
printf("New array\n");
for (int i=0; i<new_size; i++)
printf("%d ", array[i]);
printf("\nArray address: %d\n", array);
free(array);
return 0;
}
My professor wrote the following code:
template <class T>
Set<T>& Set<T>::operator=(const Set<T>& set) {
if (this == &set) return *this;
T* data_temp = new T[set.size];
try {
for (int i = 0; i < size; ++i) {
temp_data[i] = set.data[i];
}
} catch (...) {
delete[] temp_data;
throw;
}
delete[] data;
data = temp_data;
size = maxSize = set.size;
return *this;
}
And he pointed that temp_data[i] = set.data[I]; calls operator=, and I am wondering why this doesn't leak memory?
For example if operator= failed in the 4th loop then we are deleting temp_data, but what about the values of the first 3 cells in temp_data which were allocated inside operator= code? we aren't freeing them.
For example if operator= failed in the 4th loop then we are deleting temp_data, but what about the values of the first 3 cells in temp_data which were allocated inside operator= code? we aren't freeing them.
new[] allocates the entire array and constructs all of the T objects in it, before the loop is reached. delete[] destructs all of the objects in the array, and deallocates the entire array. So, it is the responsibility of T's constructor and destructor to initialize and finalize T's data members properly.
The loop merely updates the content of the data members of the objects in the array. It is the responsibility of T::operator= to copy and free T's data members properly as needed.
There is no leak in this Set::operator= code. However there is a minor mistake - the loop needs to use set.size instead of size.
for (int i = 0; i < set.size; ++i)
The new array is allocated to set.size number of elements, so that is how many elements the loop needs to copy.
Using size for the loop, if the Set being assigned to is smaller than the Set being copied, the new array won't copy all of the elements. And if assigning to a Set that is larger, the loop will go out of bounds of both arrays.
If you are experiencing a leak, it would have to be in either T::operator= or in T::~T(), neither of which you have shown. Assuming Set::Set() and Set::~Set() are initializing and freeing data properly, this is.
Lets remove some complications from this code. Lets assume T == int and instead of storing many ints we only store one:
int_store& int_store::operator=(const int_store& set)
{
int* temp_data = new int; (1) allocate
try
{
*temp_data = *set.data; (2) assign
}
catch (...)
{
delete temp_data; (3) free temp
throw;
}
delete data; (4) free old
data = temp_data;
}
The method has one allocation int* temp_data = new int (1). It the tries to assign the other sets data to that temp value (2). When this fails the temp has to be deleted (3) otherwise we can replace the old data with the new data stored in temp_data and before doing that we have to delete the old data (4).
There is no allocation in the try block. All memory allocated in the function is either deleted (when assignment fails) or it is used to replace the old data, in which case the old data is deleted before.
If data is an array instead of a single int (almost) nothing changes and there is no leak. The elements you worry about are already allocated in the line T* data_temp = new T[set.size]; and then delete[] temp_data; will delete all of them.
I have made for school purposes my own take on a dynamically allocated array using templates.
While what I'm about to ask works, I don't know how and why and I've reached the point where I need to know.
template <typename TElement>
DynamicArray<TElement>::ensureCapacity () {
if (capacity >= elemNumb) {
return; //we have space to store the values
}
//we need to allocate more space for the values
TElement *auxArray = myArray;
//create space to hold more numbers
capacity = capacity * 2;
myArray = new TElement[capacity];
//copy the values
for (int i = 0; i < size; i++) {
myArray[i] = auxArray[i];
}
//release the memory
delete[] auxArray;
}
I need to know: TElement *auxArray = myArray; How does this work ? is it using pointers, are elements copied one by one ? I need to understand how it works so that I can figure out the complexity of my algorithm. I don't mind if some one tells me the complexity but the real answer I'm looking for is how does that work ?
Also myArray = new TElement[capacity]; I do this before deleting the old myArray does this delete the old one ? or is it still floating somewhere in memory in one form or another ?
This
TElement *auxArray = myArray;
just means that auxArray points to whatever myArray is pointing to. There is no copying of anything else, it is just a pointer copy.
This
myArray = new TElement[capacity];
means that myArray now points to a new, dynamically allocated TElement array. The expression doesn't delete anything. But auxArray is pointing to what myArray was pointing before this assignment, so when you delete auxArray, you release the resources originally pointed to by myArray.
The code
I'm having a problem with it handling strings. Whenever I try a string, I get a lovely little error code:
Unhandled exception at 0x77e815de in arraytest.exe: 0xC0000005:
Access violation reading location 0xabababab.
It handles int, double, and char just fine. I also tried the exact same test string I was using (the alphabet) as a char* and it did that fine too. It just pukes on strings, for a reason that I cannot quite fathom. I really don't know where to go with it next. Any suggestions?
You have a problem with your reallocation code in push_back
template<class type>
void DynamicArray<type>::push_back(type newValue)
{
++_size; // <=== **
if (_size > _capacity) // If size larger than capacity
{
_capacity *= CAPACITY_MULT; // double capacity
type* tempArray = new type[_capacity];// Create temporary array with new capacity
// Copy array values into temporary array
for (int i = 0; i < _size; i++) // <=== **
{
tempArray[i] = dynArray[i];
}
// Delete dynArray
delete[] dynArray;
// Insert new value at end of temporary array
// Set dynArray to temporary array
dynArray = tempArray;
}
dynArray[_size - 1] = newValue;
}
You start by increasing the size of the current container before checking if there is room for the new element. Then you use the new size when copying the old values to a new array.
This might seem to work for primitive types, but a std::string will try to copy its own internal data (which isn't there) and liklely cause an access violation.
In my class I have a dynamically allocated array of pointers. My declaration:
array = new Elem* [size];
for (int i = 0; i < size; i++) {
array[i] = NULL;
}
So there is an array of pointers, where each pointer points to a simple Elem struct.
The main question is, how should I properly deallocate the array. If I use only:
for (int i = 0; i < size; i++) {
delete array[i];
}
Valgrind reports 1 not-freed block, which is traced to the line where 'array = new Elem* [size];' states.
On the other hand if I add to the previous code:
delete array;
Which I thought is correct, valgrind reports 0 not-freed blocks, which is perfect, BUT it reports
Mismatched free() / delete / delete []
exactly on the line where 'delete array;' is. I tried 'delete []array' too, but that's just "1 not-freed blocks" too then! If somebody could explain me the proper way it would be much appreciated.
EDIT:
So using:
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
is working probably fine. It is working in one of my classes (I have two similar) the other still reports some small leak. I would think it's just a minor bug somewhere, but valgrind still points to the line where
array = new Elem* [size];
stands.
EDIT2:
I solved this as well, thank you for your exhausting contribution!!
You need:
delete [] array;
Because it's an array.
I just noticed your note that you tried this too - it's the proper thing to do so I don't know why you'd still be getting an error.
Edit: This deserves a more thorough explanation.
When you create a pointer using new, the pointer may be to a single element or an array of elements depending on the syntax you use. But the pointer type is the same in both cases! The compiler relies on you to know what the pointer points to and treat it accordingly.
Elem ** single = new Elem*; // pointer to one pointer
single[0] = new Elem; // OK
single[1] = new Elem; // runtime error, but not compile time
Elem ** array = new Elem* [2]; // pointer to array of pointers
array[0] = new Elem; // OK
array[1] = new Elem; // OK
When you delete a pointer, the destructor is called for the object it points to or for each element of the array. But since the pointer type is the same in each case, the compiler relies on you to give it the proper syntax so it knows what to do.
delete single;
delete [] array;
In your case the elements of the array are pointers also, and pointers don't have destructors. That means those pointers won't be deleted and will become memory leaks if you don't delete them first. You were correct to have a loop to delete them individually before the final delete.
You should free everything in the array (if dynamically allocated) and then free the array itself.
for (int i = 0; i < size; i++) { // only free inside if dynamically allocated - not if just storing pointers
delete array[i];
}
delete[] array; // necesarry
The syntax for deleting an array is like this:
delete[] array;
Your for loop to delete the objects pointed to by the elements of the array is fine. The deletion of the array itself is the only problem. You need both the for loop and then the delete[] to dispose of the array itself.
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
I suspect that you have tried using the for loop, or the delete[], but not both together. And if when you do that you still have leaks or errors, then you would need to show us the code that allocates the pointers that are elements of the array.
Using std::vector<> instead of an array would mean that you could stop worrying about these nitty gritty details and move to higher level of abstraction.
In this case, you need both.
for (int i = 0; i < size; i++) {
delete array[i];
}
delete[] array;
You call delete exactly once for each time you called new.
Note that although you need to call delete[] array here (because you allocated it with new[]), the delete[] operator does not call the destructors on the objects pointed to by elements of the array. This is because the delete[] operator calls destructors on objects in the array, and your array contains pointers but not objects. Pointers do not themselves have destructors.