I have this code for managing dynamic collection List, which is mostly inspired with .NET System.List collection, but this is written in normal C++.
void List<T>::Insert(int index, T item)
{
if(index > GetLength() && index >= 0)
throw new StandartException("Index was out of array range");
if(GetLength()==length)
{
T * newl = new T[length + 4];
this->CopyTo(newl);
delete[] this->items;
this->items = newl;
length += 4;
}
T * store = new T[length];
CopyTo(store, index);
store[index] = item;
CopyTo((store + index + 1), index, GetLength() - index);
used++;
delete[] items;
items = store;
}
template <typename T>
void List<T>::CopyTo(T * destination, int start, int count)
{
for(int i = start, c = 0;i < GetLength() && c < count;i++, c++)
*(destination + i) = items[i];
}
So there is method Insert, which has to insert item on specified index in array.
For first, I'm checking if is index specified between 0 and Length + 1 (because I need to have a option to add item on the ond of collection). Then I'm testing if it is not end of allocated array (GetLength() = gets number of elements in array, length = number of allocated space for elements). If it is, I'm allocating new space for array, copying actual elements, freeing old storage and setting pointer to new address.
After that I'm allocating new space again. I'm copying actual elements from zero to index - 1, setting item which has to be inserted on it's position and copying other old elements to thier indexes (their previous index + 1). On the end I'm freeing old space and adding new.
ERROR: I started debugging. Everything was normal, I've run Insert for first without problem, but on first deletion (delete[] this->items; in if block) I've received this error:
Does anybody know why am I getting this and how can I repair it? I think that I haven't gone throught array range anywhere.
Please help.
Your problem is this line:
T * store = new T[length];
You insert an item, but don't allocate an array that is any larger than before. When you go to CopyTo the new array, you overflow the array.
Related
I'm currently learning C++ and for my current goal I want to fill values from vector A into vector X. vector X must not be larger than 20. To archive this I have a function that checks if the current vector has space left. If no space is left, it replaces the current vector with a new vector from a template (which already contains some entries, that have to be the same for all the vectors):
int ChunkedBufferBuilder::checkNewBuffer() {
int space_left = chunk_size - super::current.size();
if (space_left == 0) {
bufVec.push_back(super::current);
super::current = tpl;
space_left = chunk_size - super::current.size() ;
}
return space_left;
}
bufVec is another vector holding all vectors that have reached a size of 20. This function returns always the remaining amount of "free" entries in the current Vector.
To prevent having to insert every single value from the input vector in to the smaller vectors, I'm trying to use the insert function here:
ChunkedBufferBuilder* ChunkedBufferBuilder::push_back(const std::vector<uint8_t> &vec) {
auto pos = 0;
const auto size = vec.size();
while (pos < size) {
const int space_left = checkNewBuffer();
const int to = (space_left > size - pos) ? size : pos + space_left;
auto fromPtr = vec.at(pos);
auto toPtr = vec.at(to);
int size = super::current.size();
super::current.insert(super::current.end(), fromPtr, toPtr);
size = super::current.size();
pos = to;
}
return this;
}
Note, that the second size = super::current.size() was placed there by me for helping to debug. In the following images I have set two breakpoints. One on the line where insert is called and the other one on the pos = to assignment.
The documentation of std::vector states that:
The vector is extended by inserting new elements before the element at the specified position, effectively increasing the container size by the number of elements inserted.
Thus I expect that the size increases by the amount of elements, that I added. But when I run the debugger:
I get these values at the first breakpoint:
And at the second breakpoint size only increased by one:
However on the second pass of the while loop, it then tries to insert another twelve values (size is still 8 so 20 - 8 == 12):
And then suddenly the size jumps to 22:
This is currently breaking my program and I'm pretty much clueless why my code behaves in the way it currently does.
In this snippet:
auto fromPtr = vec.at(pos);
auto toPtr = vec.at(to);
super::current.insert(super::current.end(), fromPtr, toPtr);
you are inserting fromPtr copies of the value toPtr (i.e. overload (3)). From your description, it appears you mean to use overload (4):
super::current.insert(super::current.end(), vec + pos, vec + to);
which copies elements from vec to super::current.
I'm writing my own array sorting method and I have created a duplicate array to stored the objects as they are stored. The arrays are both arrays of pointers and so I need to delete my temporary array without deleting the items it points to. In the code snippet below I am leaking memory as I either delete all the items or do not delete anything.
//In constructor initialiser list
m_listArray( new PathFindingTile*[maxSize] )
void sort()
{
auto** sorted = new PathFindingTile*[m_size];
sorted[0] = m_listArray[0];
for (int i = 1; i < m_size; i++)
{
sorted[i] = m_listArray[i];
for (int j = i; j - 1 >= 0; j--)
{
if (*m_listArray[j] < *m_listArray[j - 1])
{
PathFindingTile* temp = sorted[j - 1];
sorted[j - 1] = m_listArray[i];
sorted[j] = temp;
}
else
{
sorted[i] = m_listArray[i];
break;
}
}
}
m_listArray = sorted;
//Both 'delete sorted' and 'delete[] sorted' delete the contents of sorted, but I'd only like to delete the array pointer
delete sorted;
}
How can I transfer the duplicated list back to the original list without leaking memory?
m_listArray = sorted;
On this line, you leak the array that m_listArray was pointing at before the assignment.
You must delete the array before (the only) pointer to it is overwritten. Also, delete is wrong for deleting pointers from new[]. delete[] is correct:
delete[] m_listArray;
m_listArray = sorted;
P.S. It is not a good idea to have bare pointers to owned memory. I recommend using std::vector instead. Also, it should not be necessary to allocate a new array in order to sort one. You could simply swap elements within the array.
I think you just remove pointer to the first element in the array. I believe you need to release the array with the follow command.
delete[] sorted
Read more about delete and delete[] [delete vs delete[]]1
I'm Java guy trying to solve discrete knapsack problem in c++. However, I'm having trouble with pointers. I have an object with a field
Item ** items;
representing array of items to choose from. I also created a method to add an item which works like insertion sort (at least I hope so).
void Knapsack::addItem(Item item) {
int k = itemCount - 1;
if (this->items[k] != NULL) {
return;
}
while (k > 0 && this->items[k - 1] == NULL) {
k--;
}
if (k == 0) {
this->items[0] = &item;
} else {
int i = 0;
while (i < k && item < *(this->items[i])) {
i++;
}
for (int n = k; n > i; n--) {
this->items[n] = this->items[n - 1];
}
this->items[i] = &item;
}
}
Later, in my main I invoke the method by
knapsack->addItem(*(new Item(values.at(0), values.at(1))));
values being a vector of ints. The method itself seems to work fine, however, debugger shows that everytime I invoke the method with new Item, the previous values already put in my array are set to the same values as the new item.
(ex. if items[0] has value of 5, and I invoke the method with an item valued as 10, the items[0] instantly is set to 10).
Why are the values overwritten? I am creating a new object everytime I invoke the method.
EDIT:
Problem was fixed by replacing
this->items[0] = &item;
this->items[i] = &item;
with
this->items[0] = new Item(item.getWeight(), item.getValue());
this->items[i] = new Item(item.getWeight(), item.getValue());
SECOND EDIT:
The answer shows better (and probably correct) way to do this. Now the function takes a pointer instead of an object.
void Knapsack::addItem(Item * item);
this->item[i] = item;
knapsack->addItem(new Item(values.at(0), values.at(1)));
You are storing a pointer to a temporary copy of an Item object in the array in your addItem function, once the function returns the temporary object will be destroyed and you will be left with an invalid pointer. Make sure to allocate an Item object on the heap and passing a pointer to your addItem function or just use a vector of type std::vector<Item> and save your objects in there.
I tried to write a function that gets an object ("Stone") and deletes the stone from a given array. code:
void Pile::del_stone(Stone &s)
{
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i <size;++i)
{
if (s != Pile_arr[i])//if the given object to delete is different from the current
{
temp[i] = Pile_arr[i];//copy to the new array
}
else
{
i--;
}
}
Pile_arr = temp;
set_size(this->size - 1);
temp = NULL;
delete[] temp;
}
Pile_arr is a member of Pile class.
The problem is that i get an infinite loop, because i decrease i. I cant figure out how to solve this issue. Any ideas?
Use two indexes: i and j. Use i to know which element of the original array you are looking and j to know where to put the element in temp.
You need to use a separate counter to track where new elements should be placed.
I have used n below:
Stone *temp = new Stone[size - 1];
int n = 0; // Stores the current size of temp array
for (int i = 0;i <size;++i) {
if (s != Pile_arr[i]) {
temp[n++] = Pile_arr[i];
}
}
It's also worth considering the case where s is not found in the array, as this would cause a runtime error (Attempting to add size elements to an array of size size - 1).
Using a STL container would be a far better option here.
This function will:
Allocate a new array of length size-1
Search for the intended object
If you find it, copy it to the same exact position in the array
If you don't --i
Finally, ++i
First of all, this function is bad for 3 reasons:
It only copies one item over--the given item. You have an array with only 1 object.
It copies the item from index to index. Since the final array is one smaller, if the object is at the max original index, it will be out of bounds for the new array.
If the object is not immediately found, the array will get stuck, as you decrease the index, and then increase it using the loop--you'll never move again.
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i
Instead:
Cache the found object, then delete it from the original array or mark it. temp = found object
Copy the array, one by one, without copying empty spaces and closing the gap. Copy temp_array[i] and increment i if and only if temp_array[j] is not marked/deleted. Increment j
Decide where to put the found object.
Once again, you can decide to use separate indexes--one for parsing the original array, and one for filling the new array.
I need some assistance with a C++ project. What I have to do is remove the given element from an array of pointers. The technique taught to me is to create a new array with one less element and copy everything from the old array into the new one except for the specified element. After that I have to point the old array towards the new one.
Here's some code of what I have already:
I'm working with custom structs by the way...
Data **values = null; // values is initialized in my insert function so it is
// populated
int count; // this keeps track of values' length
bool remove(Data * x) {
Data **newArray = new Data *[count - 1];
for (int i = 0; i < count; i++) {
while (x != values[i]) {
newArray[i] = values[i];
}
count -= 1;
return true;
}
values = newArray;
return false;
}
So far the insert function works and outputs the populated array, but when I run remove all it does is make the array smaller, but doesn't remove the desired element. I'm using the 0th element every time as a control.
This is the output I've been getting:
count=3 values=[5,6,7] // initial insertion of 5, 6, 7
five is a member of collection? 0
count=3 values=[5,6] // removal of 0th element aka 5, but doesn't work
five is a member of collection? 0
count=4 values=[5,6,5] // re-insertion of 0th element (which is stored in
five is a member of collection? 0 // my v0 variable)
Could anyone nudge me in the right direction towards completing this?
First of all, your code is leaking memory like no good! Next you only copy the first element and not even that if the first element happens to be the one you want to remove. Also, when you return from your function, you haven't changed your internal state at all. You definitely want to do something along the lines of
Data** it = std::find(values, values + count, x);
if (it != values + count) {
std::copy(it + 1, values + count, it);
--count;
return true;
}
return false;
That said, if anybody taught you to implement something like std::vector<T> involving reallocations on every operation, it is time to change schools! Memory allocations are relatively expensive and you want to avoid them. That is, when implementing something like a std::vector<T> you, indeed, want to implement it like a std::vector<T>! That is you keep an internal buffer of potentially more element than there are and remember how many elements you are using. When inserting a new element, you only allocate a new array if there is no space in the current array (not doing so would easily result in quadratic complexity even when always adding elements at the end). When removing an element, you just move all the trailing objects one up and remember that there is one less object in the array.
Try this:
bool remove(Data * x)
{
bool found = false;
// See if x is in the array.
for (int i = 0; i < count; i++) {
if (x != values[i]) {
found = true;
break;
}
}
if (!found)
{
return false;
}
// Only need to create the array if the item to be removed is present
Data **newArray = new Data *[count - 1];
// Copy the content to the new array
int newIndex = 0;
for (int i = 0; i < count; i++)
{
if (x != values[i])
newArray[newIndex++] = values[i];
}
// Now change the pointers.
delete[] values;
count--;
values = newArray;
return true;
}
Note that there's an underlying assumption that if x is present in the array then it's there only once! The code will not work for multiple occurrences, that's left to you, seeing as how this is a school exercise.