Trying to dynamically grow a static array c++ - c++

So I have to dynamically grow a static array in this struct I've made (I COULD use vectors but it specially asks me to use a static array and copy the elements so please don't ask me to use vectors).
Problem is I get segmentation faults and I don't know why. When I create a new instance of my object it sets an array with a length (currently 5 to test). I then run this code when resizing the array but it isn't working.
if (used == (length-1)) {
length *= 2;
T* newArr = new T[length];
for (int i = 0; i < used; i++) {
newArr[i] = items[i];
cout << "Copied" << endl;
}
items = newArr;
}
So it seems to copy to addresses over to the new array OK and seems to only copy the appropriate number of items. Used determines how many items have been added whereas length holds the size of the entire array. Such that when I create a new array the length should be double how many are used. When I try and assign items to newArr I get a segmentation fault so I'm wondering if that code is correct or if it's crashing there. I;ve tried debugging it line by line but can't tell if it's breaking there or not.

Q: "I COULD use vectors but it specially asks me to use a static array and copy the elements so please don't ask me to use vectors..."
A: Then the question is fundamentally flawed ;) You SHOULD use vectors ;)
If you really want to amuse your instructor, I'd encourage you to usemalloc(), realloc() and free() instead of "new" and "delete" ;)
Meanwhile - you're probably getting a segmentation fault by overwriting "newArr[]". "newArr[]" might be too small if "used" is a lot bigger than length.
Just a guess - using a debugger would clearly show you exactly what's happening.
Q: What compiler and debugger are you using?

Do a
delete[] items;
before the reassignment

Related

Resizing an array of objects

i'm trying to do a homework in c++ where I can't use STD container classes such as vector,map,etc. Suppose we have the following archive:
2
El juego de Ender-Orson Scott-Tor Books-980.275.246-1985-6000
890365.2
2
The following-Lily Tyler-Tor Books-980.275.246-1985-6000
890365.2
For explanation purposes lets assume the number 2 means that a book is from X category, in this case 2 means is a fiction book, the next line after 2 is just the basic book data (name,author,publishing house,isbn,year,price) and the next line after that is just something that we are going to call CCF that is just another code for these types of books from the fiction category.
I'm just stuck on the next following part, I do know how to create an array of objects without container classes, but I do not know how to resize this array, i've been hearing about realloc, but i don't know how to use it with object array types. Libro is the parent of Ficcion and i'm trying to store Ficcion types in a polymorphic array of Libro because later on I have to introduce more classes in the same array, but for learning purposes i'm trying to resize with just the ficcion class, that being said, I do know the next following code is wrong because i'm using malloc and allocating the child object with new and then reallocating, but as I said I don't really get how to do this at all cause if you see the code you can tell that a new child object is created every 3 times inFile has executed getline, if you think something's missing please let me know, but I think what i've exposed covers the main issues of this question. I'm just asking for some enlightment of information when you have to deal with these types of arrays and you need to resize them, and I also know this would be way more easier with the container class but I can't use it this time. Thanks in advance! have a great day/night!
void BookManager::dataLoading(char* fileName){
//Arbitrary size to be resized later on (this is the array declared as **libro in the .h file)
libros = (Libro**)malloc(1 * sizeof(Libro**));
//file-in variable
std::ifstream inFile(fileName);
char type[10];
//counter
int i = 0;
//First getline
while (inFile.getline(type,sizeof(inFile)) && i < 2){
//Book Info; Second Getline
char bookInfo[100];
inFile.getline(bookInfo, sizeof(inFile));
//Additional book information; Third getline
char additional[60];
inFile.getline(additional, sizeof(inFile));
//Child creation
if (type[0] == '2'){
this->separateData(bookInfo);
//Ficcion constructor creating an object to store in the libros polymorphic array
libros[i] = new Ficcion(this->bookData[0], this->bookData[1], this->bookData[2], atof(this->bookData[3]), atoi(this->bookData[4]), atoi(this->bookData[5]), atof(additional));
}
i++;
//Failed reallocating
libros = (Libro**)realloc(libros, i+1 * sizeof(Libro**));
}
// This one is just testing if the array worked but i get an unhandled exception when i=1;
for (int i = 0; i < 2; i++){
std::cout << libros[i]->getTitulo() << '\n';
}
inFile.close();
}
UPDATE solution:
Since this is an array of pointers, as suggested down below i created a function where it resizes it and deletes the old one, returning the new one with the old data and a free space to store. So far this is working, thanks a lot guys!
Libro** BookManager::resize(Libro** arr,int size){
Libro** resized = new Libro*[size];
for (int i = 0; i < size-1; i++){
resized[i] = arr[i];
}
delete[]arr;
return resized;
}
malloc, realloc, etc.. are C library functions. Your question carries the C++ tag, not C.
In C++, objects are allocated with new, and deallocated with delete. This includes arrays.
To resize an existing array, you use new to allocate a new array, with the new size, copy into it the elements in the existing array, then deallocate the old array with delete.
(This is not 100% technically true, but this is likely what you are expected to do as part of your assignment).

Use of pointer to vector which involved the use of 'new'

I would like to create a vector of pointers to struct
vector<myStruct*> vec
For elements in the vector, not all of them contain data. Some of them may point to NULL.
So, should I create space by new in each of the element first
for(int i = 0; vec.size() ;i++){
if (thisSpaceIsValid(i))
vec.at(i) = new myStruct;
else
vect.at(i) = NULL;
}
The problem comes:
-If I use new for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector(vec here)?
-If later I use delete to free the memory, would the problem of speed still bother me?
If I use "new" for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector("vec" here)?
You can do that.
Let's say the size of your vector is M and you only need N of those elements to have pointers to objects and other elements are null pointers. You can use:
myStruct* objects = new myStruct[N];
and then, use:
for(int i = 0, j = 0; vec.size(); i++)
{
if (thisSpaceIsValid(i))
{
if ( j == N )
{
// Error. Do something.
}
else
{
vec[i] = objects+j;
++j;
}
}
else
{
vect[i] = NULL;
}
}
You have to now make sure that you are able to keep track of the value of objeccts so you can safely deallocate the memory by using
delete [] objects;
PS
There might be a better and more elegant solution to your problem. It will be worth your while to spend a bit more time thinking over that.
EDIT:
After reading the question again, it seems I misunderstood the question. So here is an edited answer.
If you only need to execute the code during some kind of initialization phase, you can create all the instances of myStruct in an array and then just point to those from the vector as already proposed by R Sahu. Note that the solution requires you to create and delete all instances at the same time.
However, if you execute this code several times and/or don't know exactly how many myStruct instances you will need, you could overwrite new and delete for the struct and handle memory allocation yourself.
See Callling object constructor/destructor with a custom allocator for an example of this. See the answer by Jerry Coffin.
BTW - you don't need vec.at(i) as you are iterating from 0 to size. vec[i] is okay and should perform a better.
OLD ANSWER:
You can do
vector<myStruct*> vec(10000, nullptr);
to generate a vector with for instance 10000 elements all initialized to nullptr
After that you can fill the relevant elements with pointer to the struct.
For delete just
for (auto e : vec) delete e;
cause it is safe to do deleteon a nullptr
If you need a vector of pointers, and would like to avoid calling new, then firstly create a container of structs themselves, then assign pointers to the elements into your vec. Be careful with choosing the container of structs. If you use vector of structs, make sure to reserve all elements in advance, otherwise its elements may move to a different memory location when vector grows. Deque on the other hand guarantees its elements don't move.
Multiple small new and delete calls should be avoided if possible in c++ when performance matters a lot.
The more I think about it, the less I like #RSahu's solution. In particular, I feel memory management in this scenario would be a nightmare. Instead I suggest using a vector of unique_ptr's owning memory allocated via custom alloctor. I believe, sequential allocator would do.

Memory errors in array resize

So I'm trying to make a template class for a heap. I'm trying not to use any of the STL classes (professor's rules and whatnot) so rather than use a vector I use a dynamically allocated array. However, when I run the program and input enough data into the heap for it to trigger the resizing function, it springs a bunch of memory errors. Some gdb work narrowed it down to this function:
template <class T>
T* Heap<T>::resize()
{
T* temp; //temp variable for storage
heap_capacity *= 2; //double capacity
temp = new T[heap_capacity]; //create new enlarged array
for (int i = 0; i < heap_size; ++i)
{
temp[i] = heap_arr[i]; //copy elements from previous array to current
}
delete [] heap_arr; //delete old array
return temp; //return new array
}
Pretty standard stuff, tbh. It requires whatever T is to have an assignment operator, but I was testing it using plain old integers. This isn't the first time I've written this code, but it is the first time I've written it for a template. Does the problem lie in this function, or is it somewhere else?
Edit: I played around with the code a little bit more in gdb. Turns out the program errors out right after I allocate memory for temp. This is strange, because I do the same thing for the original heap_array in the constructor. I'll be poking around a bit more, but is my syntax wrong for the "new" statement? heap_capacity is valid, btw, so that's not the problem...
It looks like you need to set heap_arr to point to the new expanded memory. It would certainly make sense for the resize method to take care of this:
delete [] heap_arr;
heap_arr = temp;
return heap_arr;
You also need to be sure that the heap_size is less than heap_capacity.
Well, I've figured out why I was getting the error. Turns out my check to see if the size of the heap was equal to the capacity forgot a crucial part: the extra 0 at the top of the array. The heap is 1-based (as opposed to 0-based) so the fix was simple: change the heap_size == heap_capacity statement to heap_size == heap_capacity-1... an important distinction. Thank you all for your help.

Why can't initial length be 1 in a dynamically-allocated array?

Let's say we start out with:
int *newArray = new int[1];
And then later have something like:
ifstream inputFile("File.txt");
Counter=0;
while (inputFile >> newValue)
{
newArray[Counter] = newValue;
Counter++
}
If I try to pull 100 lines from the text file, the program will eventually crash. However, if I had used
int *newArray = new int[100];
originally, it doesn't crash.
If it's dynamically allocating memory, why does it need an initial value more than 1? That makes no sense to me. Having to define any initial length beyond a small number such as 1 or 10 defeats the whole purpose of dynamic memory allocation...
EDIT: This is for school, we aren't allowed to use vectors yet.
The language will not "dynamically allocate memory" for you. It is your responsibility to allocate and reallocate your arrays so that their sizes are sufficient for your purposes.
The concept of "dynamic allocation" in C++ never meant that memory will somehow allocate itself automatically for you. The word "dynamic" in this context simply means that the parameters and lifetime of the new object are determined at run time (as opposed to compile time). The primary purpose of dynamic memory allocation is: 1) to manually control object's lifetime, 2) to specify array sizes at run-time, 3) to specify object types at run-time.
The second point is what allows you to do this
int n = ...; // <- some run-time value
int *array = new int[n];
which is not possible with non-dynamically allocated arrays.
In your example, you can allocate an array if size 1 initially. Ther's nothing wrong with it. But it is still your responsibility to allocate a new, bigger array, copy the data to the new array and free the old one once you need more space in your array.
In order to avoid all that hassle you should simply use a library-provided resizable container, like std::vector.
It's not dynamic in the sense that it can dynamically resize itself. It's dynamic in the sense that its size can be chosen dynamically at runtime, instead of compile time. One of the primary philosophies of C++ is that you don't pay for what you don't use. If dynamic arrays worked the way you are asking, that would require bounds checking, something I don't need, so I don't want to pay for it.
Anyway, the problem is solved with the standard library.
std::vector<int> vec;
...
while (inputFile >> newValue)
{
vec.push_back(newValue);
}
Isn't that much nicer? You don't even have to keep track of the size, because vector keeps track of it for you.
If you can't use vector, then you've got a lot of work ahead of you. The principle is essentially this. You keep 2 additional integer variables. One to indicate the number of values you are using in your array, and one to indicate the current capacity of your array. When you run out of room, you allocate more space. For example, here is a poor man's non-exception safe version of a vector:
int size = 0;
int capacity = 1;
int array = new int[capacity];
while (inputFile >> newValue)
{
if (size == capacity)
{
capacity *= 2;
int * newArray = new int[capacity];
for (int i=0; i<size; ++i)
newArray[i] = array[i];
delete [] array;
array = newArray;
}
array[size++] = newValue;
}
You're only creating space for one int but trying to store several, of course it crashes. Even if you created it with size 100 it'd still crash when you tried to save the 101'th value.
If you need an automatically resizing container check out std::vector.
#include <vector>
std::vector<int> data;
while (inputFile >> newValue)
{
data.push_back(newValue);
}
This will work until your process runs out of memory.

C++ - is a pointer to a single value same as a size 1 dynamic array?

I have this snippet of code which I am considering to simplfy:
if (numberOfResults > 1)
{
trackResult_ = new TrackResult[numberOfResults];
for (int i=0; i < numberOfResults; i++)
{
// Make a deep copy
TrackResult tempResult = result[i];
TrackResult * clone = new TrackResult(tempResult);
trackResult_[i] = *clone;
}
storeJointResults(trackResult_, numberOfResults);
}
else
{
trackResult_ = new TrackResult(*result);
}
(I have 'no choice' but to use a simple dynamic array here. Vectors are deemed 'too complicated' at my workplace)
I am wondering if I can get away with
// even if we just have one result, we init an array size of one
trackResult_ = new TrackResult[numberOfResults];
However, I have in several points check for the number of results and act accordingly
if (numberOfResults_ == 1)
{
velocity = trackResult_.velocity;
}
Would those code still work? If not, why?
The array of size 1 does not need to be a special case.
When you allocate a dynamic array you are given a pointer to the first element. If the array is of size 1, this is pretty much indistinguishable from just having allocated a single instance of the object.
Your special case usage would work if you changed the . to an ->
However I'd recommend not special-casing it and just use trackResult_[0].velocity
No, you need to ensure you match the correct scalar delete or array delete[] depending on whether you say new TrackResult[n]; or new TrackResult;.
Also, this leaks memory for each loop iteration:
TrackResult tempResult = result[i];
TrackResult * clone = new TrackResult(tempResult);
TrackResult_[i] = *clone;
How are vectors too complicated? If anything, the simplify your code.
I agree with Alex, using the . operator on a pointer is not my recommended style either, so those other points ought to be changed anyhow, and thus not discourage you from simplifying the piece of code you mention.