I am trying to add an array to my Object which contains dynamic array
MyCollection.h
template <typename T>
MyCollection<T>::MyCollection(int size)
{
arraySize = size;
anArray = new T[size];
}
template <typename T>
MyCollection<T>::MyCollection(MyCollection<T>& coll)
{
arraySize = coll.arraySize;
anArray = new T[arraySize];
for (int i = 0; i < arraySize; i++)
{
SetValue(coll.GetValue(i), i);
}
}
template <typename T>
MyCollection<T>::MyCollection(T* myArray, int size)
{
anArray = myArray;
arraySize = size;
}
template<typename T>
void MyCollection<T>::AddAll(T pArray[], int size)
{
int plusSize = size - 1;
int arrayIterator = 0;
arraySize += size;
for (int i = size; i < arraySize - plusSize; i++)
{
anArray[i] = pArray[arrayIterator];
arrayIterator++;
}
}
Main
MyCollection<string> B = MyCollection<string>(new string[3], 3);
B.SetValue("C", 0);
B.SetValue("D", 1);
B.SetValue("E", 2);
string C[3];
C[0] = "X";
C[1] = "Y";
C[2] = "Z";
B.AddAll(C, 3);
B.Display();
In the AddAll method I have error with acces violation. When I add watch anArray[i] = . Is there any idea why that happens? Is it problem with copy construcotr or so ?
In AddAll(), you need to resize the raw array anArray, there is no resizing going on (you just change the numeric value of arraySize, but do not allocate more memory). So you need something like
delete[] anArray;
// ...
anArray = new T[arraySize];
You may also think whether you want to copy the old elements into the newly allocated array, in which case you first have to reallocate with a temporary pointer, then copy into it, then delete the original anArray, and finally assign the temporary pointer to the original anArray, something like:
// save the old size
int oldSize = arraySize;
arraySize += size;
T* tmp = new T[arraySize];
// copy from anArray into tmp, use oldSize
// for(...){...}
delete[] anArray;
anArray = tmp;
Related
I simulated a vector but the constructor doesn't work; when I call pop() function it assigns garbage value to my old object in vector class.
vector(vector &v) {
vec = new T[v.size()];
memcpy(vec, v,v.size());
size_arr = v.size();
}
here's entire code:
#include <iostream>
using namespace std;
template <typename T>
class vector {
int size_arr;
T * vec = new T;
public:
vector(/*int _size*/) {
vec = new T[0];
size_arr = 0;
};
~vector() {
size_arr = 0;
delete[] vec;
};
vector(vector &v) {
vec = new T[v.size()];
memcpy(vec, v,v.size());
size_arr = v.size();
}
void push_back(T data) {
T *temp = new T[size_arr + 1];
for (int i = 0; i < size_arr; i++)
temp[i] = vec[i];
temp[size_arr] = data;
size_arr++;
delete[] vec;
vec = temp;
};
void push_front(T data){
int j;
T *temp = new T[size_arr + 1];
for ( j = size_arr; j >= 0;j--) {
temp[j + 1] = vec[j];
}
temp[0] = data;
delete[] vec;
vec = temp;
size_arr++;
};
void insert(int index, T data) {
int j;
T *temp = new T[size_arr + 1];
for (int i = 0; i < size_arr ;i++)
temp[i] = vec[i];
for (int i = 0; i < size_arr;i++) {
if (i == index) {
for ( j = size_arr; j >=i;j--) {
temp[j+1] = vec[j];
}
temp[j + 1] = data;
delete[] vec;
vec = temp;
size_arr++;
}
}
};
void pop() {
T *temp = new T[size_arr - 1];
for (int i = 0; i < size_arr-1;i++)
temp[i] = vec[i];
size_arr--;
delete[] vec;
vec = temp;
};
void Delete(int index)
{
T *temp = new T[size_arr - 1];
for (int i = 0; i < index;i++)
temp[i] = vec[i];
for (int i = 0; i < size_arr;i++) {
if (i == index) {
for (int j = i; j < size_arr-1;j++) {
temp[j] = vec[j + 1];
}
size_arr--;
delete[] vec;
vec = temp;
}
}
};
int search(T data) {
for (int i = 0; i < size_arr;i++) {
if (vec[i] == data) {
return i;
}
}
return -1;
};
int size() { return size_arr; };
};
int main() {
vector <int>test;
test.push_front(2);
test.push_front(3);
test.push_back(0);
test.push_back(-1);
test.insert(2, 2);
test.pop();
vector <int > test1;
test1 = test;// problem
test1.pop();
}
The problem is the line test1 = test;// problem, which does not call the copy constructor, but the assignment operator. You did not declare this operator, so the compiler will use the default implementation, which simply copies all member. So, after the assignment test1.vec and test.vec point to the same memory location.
When you change the line (and the one above it) to vector <int > test1{test};, it will call your copy constructor.
You also forgot to #include <cstring> for memcpy, which you should not use for non-POD types.
You have to multiply the size in memcpy with sizeof(T), because memcpy works on bytes, not on types. You also have to use v.vec instead of v.
Here is the fixed version: https://ideone.com/JMn7ww
I think the problem is in your copy operator. You use memcpy() which is a c function. Which should in itself not be a problem (apart from it being not so nice in many opinions). But since memcpy() is a c function, it doesn't know about types, and it takes its size arguments as a count of bytes.
the element you put in is int which is probably 4 bytes. So when your copy contstructor gets called, and the original has 3 elements, there will be 12 bytes in your array, but malloc will only copy 3 of them.
The comments of other people about not properly copying template types are right, so if you make a vector of strings, you cannot just memcpy them, and assume the result will be new strings. For this answer i was assuming you using only basic types as your template arguments like int, or double.
I want to resize the array multiple times.It does that the first time but after that, it throws me an error. When I do it the second time, I get an error _CrtIsValidHeapPointer(PUserData). Can someone help me out?
int main()
{
int size = 8;
int *arr = new int[size];
arr[1] = 25;
arr[2] = 30;
int count = 0; //to check size
for (int i = 0; i < size; i++)
{
count = count + 1;
}
cout << count << endl;
resize(arr, size);
int new_count = 0; //to confirm size change
for (int i = 0; i < size; i++)
{
new_count = new_count + 1;
}
cout << new_count << endl;
resize(arr, size);
int new_count2 = 0; //to confirm size change
for (int i = 0; i < size; i++)
{
new_count2 = new_count2 + 1;
}
cout << new_count2 << endl;
return 0;
}
void resize(int *a,int &size)
{
int newsize = 2 * size;
int *arr_new = new int[newsize];
for (int i = 0; i < size; i++) //copy everything
{
arr_new[i] = a[i];
}
size = newsize; //new value of size
delete [] a;
a = arr_new; //Pointer pointing to new array
delete arr_new;
}
There are two problems with this code:
void resize(int *a,int &size)
{
[...]
delete [] a;
a = arr_new; //Pointer pointing to new array
delete arr_new; // huh????
}
The first problem is that you are calling the delete operator twice; the first call deletes the old array (which makes sense), but then you attempt to delete the newly allocated array also (via delete arr_new). How is the caller going to able to use the newly allocated array when resize() has already deleted it before it returned?
The second problem is that you set a to point to the new array (i.e. a = arr_new;) but a is a local function-argument that goes out of scope when resize() returns, so the calling code will never see its new value. I think you want this instead:
void resize(int * & a,int &size) // note the & before a!
Passing a by reference will allow the caller to see a's new value after resize() returns.
I'm having a hard time with this little project of mine; can someone help me out? I am trying to take a pointer to an array, a number, and remove the number if it is present in the array. If the number is removed, the array shrinks. Please note at the time of running removeNumber size = 6.
main
{
int size = 5; // setting array size
int *a = new int[size]; // allocating dynamic array
// initializing array
a[0] = 0; a[1] = 10; a[2] = 20; a[3] = 30; a[4] = 40;
removeNumber(a, 10, size);
}
And now the prototype:
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
int *newArray = new int[size - 1];
if (index != -1)
{
for (int i = number; i <= size; ++i)
newArray[i] = *&arrayPtr[i + 1];
delete[] arrayPtr;
arrayPtr = newArray;
size -= 1;
}
}
Check for reference:
int check(int *arrayPtr, int number, int size)
{
for (int i = 0; i < size; i++)
{
if (arrayPtr[i] == number) return i;
}
return -1;
}
The function is wrong. First of all it has a memory leak in case when the target value is not found in the array.
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
int *newArray = new int[size - 1];
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if (index != -1)
{
//...
}
}
Secondly there is used incorrect range of indices
for (int i = number; i <= size; ++i)
^^^^^^ ^^^^^^^^^
newArray[i] = *&arrayPtr[i + 1];
^^^^^^
And you could write this expression *&arrayPtr[i + 1] simpler just like arrayPtr[i + 1].
You forgot to copy the elements of the original array before the index index. number is not a valid index.
Also it would be better if the function returned a Boolean value saying whether the operation was successful or not. You can change the size of the array in the calling function if the call was successful.
So I would write the function like
bool removeNumber( int * &arrayPtr, int n, int value )
{
int index = check( arrayPtr, number, size );
if ( index != -1 )
{
int *tmp = new int[size - 1];
int i = 0;
for ( ; i < index; ++i ) tmp[i] = arrayPtr[i];
for ( ; i < size - 1; i++ ) tmp[i] = arrayPtr[i+1];
delete [] arrayPtr;
arrayPtr = tmp;
}
return index != -1;
}
It is ok to reinvent the wheel in order to learn. However you should be aware of the standard way to handle this: using std::vector along with std::remove/std::remove_if (defined in #include <algorithm>) would make your life much simpler, with the benefit of a performant implementation.
void removeNumber(std::vector<int>& vec, int number) {
vec.erase(std::remove(std::begin(vec), std::end(vec), number),
std::end(vec));
// If you really want to shrink the vector, you can call...
vec.shrink_to_fit();
}
I also made a little demo to show you that it works as intended.
Your problem is here:
for (int i = number; i <= size; ++i)
First of all you start the iteration from the value of the number that you searched(in your case 10) and as a result you will not enter the for loop.So the correct starting value of i is the first number of the array which is 0.Then this line of code here:
newArray[i] = *&arrayPtr[i + 1];
doesn't even make sense(as a thought process not syntactically), but what i think you want to do here is just copy the correct element from the old array to the new one.
A correct implementation of the previous is the following code:
void removeNumber(int *& arrayPtr, int number, int &size)
{
int index = check(arrayPtr, number, size);
if (index != -1)
{
int *newArray = new int[size - 1];
int i = 0,j=0; //i for the old array and j for the new
while(i < size)//while we are in bounds
{
if(i==index)//if the index is the index of the given element
{ //skip this number
i++;
continue;
}
newArray[j++] = arrayPtr[i++];//copy the correct number to the correct position
}
delete[] arrayPtr;
arrayPtr = newArray;
size -= 1;
}
}
Well consider this:
int * hello = new int[10];
for (register int i = 0; i < 10; i++)
*(hello + i) = i;
int * & hello_ref = hello;
delete[] hello_ref ;
for (register int i = 0; i < 10; i++)
cout << *(hello + i) << std::endl;
Nowhello_ref can succesfully delete the memory which is allocated by new ... From a fact that the reference and pointer are very close how we do the same thing with pointer to pointer to new memory allocated
now consider this
int i = 0;
unsigned int * hello = new unsigned int[6];
for (register int i = 0; i < 6; i++)
*(hello + i) = i;
unsigned int * bye = new unsigned int[4];
for (register int i = 0; i < 4; i++)
*(bye + i) = i;
unsigned int ** del = new unsigned int *[2];
*del = bye;
*(del + 1) = hello;
delete[] * del;
delete[] * (del + 1);
Is there any way that we could delete the new allocated memory for hello and bye with the del pointer to pointer ... these could just clear the data which hello and bye pointed to ....
You just need to delete the array referenced by del:
delete[] del;
You are already deleting the arrays referenced by hello and bye:
delete[] * del;
delete[] * (del + 1);
Though this would be more idiomatic:
delete[] del[0];
delete[] del[1];
Or even better, avoid using new and delete altogether, taking advantage of modern C++ features. What you are writing looks more like C.
#include <array>
#include <numeric>
#include <tuple>
template<typename T, std::size_t N>
std::array<T, N> make_increasing_array(T initial = T())
{
std::array<T, N> array;
std::iota(array.begin(), array.end(), initial);
return array;
}
int main()
{
auto del = std::make_tuple(
make_increasing_array<unsigned int, 6>(),
make_increasing_array<unsigned int, 4>());
auto& hello = std::get<0>(del);
auto& bye = std::get<1>(del);
}
If I understand your question correctly then the answer on the 1st part of your question will be something like this:
...
int * * hello_ref = &hello;
delete[] *hello_ref;
...
About second part, you did exactly what you asked. Those 2 delete do the job. Just add delete[] del; as a final touch.
void insert(int*arr, int element,int index)
{
if (index < SIZE)
{
arr[index] = element;
}
else
{
int* new_array = new int[SIZE + 1];
int i = 0;
for (i = 0; i < SIZE; i++)
{
new_array[i] = arr[i];
}
new_array[i] = element;
SIZE++;
printArray(new_array);
}
}
I have made an insert function in C++ that will insert values at specific indices of the array.After index gets increased I made a new array and copied values from the smaller array into it.
Problem is that printArray function which is just looping to print the array does well when it is called inside the insert function otherwise when I called printArray from the main last value of the array was garbage why is that?
You need to delete the old array and return the new array in its place, e.g.:
void insert(int* &arr, int element, int index) // <<< make `arr` a reference so that we can modify it
{
if (index < SIZE)
{
arr[index] = element;
}
else
{
int* new_array = new int[SIZE + 1];
for (int i = 0; i < SIZE; i++)
{
new_array[i] = arr[i];
}
new_array[SIZE] = element;
SIZE++; // <<< NB: using a global for this is not a great idea!
delete [] arr; // <<< delete old `arr`
arr = new_array; // <<< replace it with `new_array`
}
}
LIVE DEMO
Note that all this explicit low level management of your array goes away if you start using proper C++ idioms, such as std::vector<int> instead of C-style int * arrays.