I have been making a custom vector class, however I have been bumping into a problem. The problem being that my vector just won't resize, the size stays 0.
Anyone know what the problem is?
Thanks in advance!
void resize(const int newSize) {
// If size is zero, give error
if (newSize < 0) {
throw std::out_of_range("Vector");
}
// If the given size is smaller than the size that it is now, just ignore
else if (newSize < capacity) {
return;
}
// Else, make a new array and copy everything over
T* newArr = new T[newSize];
for (int i = 0; i < capacity; i++) {
newArr[i] = data[i];
}
delete[] data;
capacity = newSize;
data = newArr;
}
EDIT 1:
Here is the push_back function where resize is needed:
template <typename T> void pushBack(Vector<T>& vector, T& value){
unsigned int oldSize = vector.size();
vector.resize(oldSize+1);
vector.at(oldSize) = value;
}
EDIT 2:
Here are the vector deffinitions:
Vector(const int newSize) {
if (newSize < 0) {
throw std::out_of_range("Vector");
}
data = new T[newSize];
capacity = newSize;
actualSize = 0;
}
Related
Im trying to create this and add push back functionality. How can i do it? I came up with this code but im very confused for 2 days because it gives this output - | -842150451 | -842150451 | -842150451 | -842150451 | -842150451 | -842150451 | -842150451 | -842150451
I will be thankful if someone can tell me how this function push_back should look or at least point me in the right direction. Also i would be thankful if you tell me where this code is doing wrong?
struct IntArray{
private:
int k;
int* first_cell;
int size; // currently occupied elements
int capacity = 8; // size of the allocated memory
public:
void create() {
first_cell = (int*)malloc(capacity * sizeof(int));
}
void random_numbers_fill(int limit) {
srand(time(NULL));
for (k = 0; k < capacity; k++) {
first_cell[k] = rand() % limit;
}
}
void push_back(int number) {
if (size == capacity) {
int* new_arr;
capacity *= 2;
new_arr = (int*)malloc(capacity * sizeof(int));
for (k = 0; k < capacity; k++) {
new_arr[k] = first_cell[k];
}
free(first_cell);
first_cell = new_arr;
first_cell[size] = number;
size++;
}
}
void print() {
for (k = 0; k < capacity; k++) {
printf("| %d ", first_cell[k]);
}
First, create() should be changed into an actual constructor. And you are missing a destructor to free the array, as well as copy/move constructors and copy/move assignment operators to manage the array (per the Rule of 3/5/0).
Second, you should be using new[] instead of malloc().
Third, regarding your push_back(), it is not a bad attempt, but it is buggy. You are not adding the number to the array at all if the current size is less than the current capacity (and your constructor is not initializing size at all). And when you do resize + copy the array, you are copying too many ints from the old array. The old array is size elements, but you are trying to copy the newly increased capacity elements from it.
With that said, try something more like this instead:
#include <iostream>
#include <algorithm>
#include <utility>
class IntArray{
private:
int* first_cell = nullptr;
int size = 0; // currently occupied elements
int capacity = 8; // size of the allocated memory
public:
IntArray()
{
first_cell = new int[capacity];
}
IntArray(const IntArray &src)
: size(src.size), capacity(src.capacity)
{
first_cell = new int[capacity];
std::copy_n(src.first_cell, size, first_cell);
}
IntArray(IntArray &&src)
: first_cell(src.first_cell), size(src.size), capacity(src.capacity)
{
src.first_cell = nullptr;
src.size = src.capacity = 0;
}
~IntArray()
{
delete[] first_cell;
}
IntArray& operator=(IntArray rhs)
{
IntArray temp(std::move(rhs));
std::swap(first_cell, temp.first_cell);
std::swap(size, temp.size);
std::swap(capacity, temp.capacity);
return *this;
}
void push_back(int number)
{
if (size == capacity)
{
int new_cap = capacity * 2;
int* new_arr = new int[new_cap];
for (int k = 0; k < size; ++k) {
new_arr[k] = first_cell[k];
}
delete[] first_cell;
first_cell = new_arr;
capacity = new_cap;
}
first_cell[size] = number;
++size;
}
void print() const
{
for (int k = 0; k < size; ++k) {
std::cout << "| " << first_cell[k] << " ";
}
}
};
That being said, you should just get rid of your manual array and use std::vector<int> instead, as it handles all of these details for you, eg:
#include <iostream>
#include <vector>
class IntArray{
private:
std::vector<int> vec;
public:
IntArray()
{
vec.reserve(8);
}
void push_back(int number)
{
vec.push_back(number);
}
void print() const
{
for (int number : vec) {
std::cout << "| " << number << " ";
}
}
};
You never initialize size in create.
Your push_back has two problems. You don't copy the number that is pushed unless you grow the array (the last two statements should be outside the if block), and the condition in the for loop should compare with size, not capacity.
print also has the wrong condition in the for loop.
I'm trying to set up the overloaded operator '=' for a custom Array class for practice, but it seems to be causing a runtime error.
class Array {
private:
static int numberOfElements; //class static variable
int size;
int* numbers;
public:
Array(int);
Array(const Array&);
~Array();
int getSize();
static int getNumberOfElements();
Array& operator =(const Array&);
};
This overloaded operator function produces the correct output, but with a runtime error:
Array& Array::operator =(const Array& newArray) {
numberOfElements = numberOfElements - size + newArray.size;
size = newArray.size;
for (int i = 0; i < size; i++)
numbers[i] = newArray.numbers[i];
return *this;
}
Before, I had
Array& Array::operator =(const Array& newArray) {
delete[] numbers;
numberOfElements = numberOfElements - size + newArray.size;
size = newArray.size;
numbers = new int[size];
for (int i = 0; i < size; i++)
numbers[i] = newArray.numbers[i];
return *this;
}
Which does not produce a runtime, but creates an array filled with garbage. numberOfElements is just tracking the total elements in all Arrays, and shouldn't be a factor in the error. I'm certain the issue is the dynamic allocation, but I can't seem to logically figure out why it would throw a runtime if I'm only overwriting the original array with newArray, and why the latter is filling with garbage even though the allocated array is being set to newArray's elements.
If newArray.size is larger than this->size, your operator= trashes memory. It needs to reallocate its numbers[] array to account for the larger size, which you were originally doing (just not in an exception-safe manner).
If newArray.size is not larger than this->size, no reallocation is needed, just copy the values from newArray.numbers into this->numbers as-is, making sure to not exceed the smaller of newArray.size or this->size.
Try something more like this:
Array& Array::operator=(const Array& newArray)
{
if (&newArray != this)
{
if (size != newArray.size)
{
numberOfElements -= size;
delete[] numbers;
numbers = NULL;
size = 0;
numbers = new int[newArray.size];
size = newArray.size;
numberOfElements += size;
}
for (int i = 0; i < size; ++i)
numbers[i] = newArray.numbers[i];
}
return *this;
}
Which can then be made safer using the copy-swap idiom using your existing copy constructor:
Array::Array(int num)
{
size = num;
numbers = new int[num];
numberOfElements += num;
}
Array::Array(const Array &srcArray)
{
size = src.size;
numbers = new int[size];
for (int i = 0; i < size; ++i)
numbers[i] = srcArray.numbers[i];
numberOfElements += size;
}
Array::~Array()
{
delete[] numbers;
numberOfElements -= size;
}
#include <algorithm>
Array& Array::operator=(const Array& newArray)
{
if (this != &newArray)
{
if (size != newArray.size)
{
Array tmp(newArray);
std::swap(numbers, tmp.numbers);
std::swap(size, tmp.size);
}
else
{
for (int i = 0; i < size; ++i)
numbers[i] = newArray.numbers[i];
}
}
return *this;
}
So, here is the header file where I implemented my own vector class in a simple way.
The problem is that even though the code compiles, the member functions pushBack and insert both do not work properly.
I'd be really glad if anyone can figure out the problem in my code or find some ways how I can get this problem resolved.
#include <iostream>
#include <new>
using namespace std;
template <typename T>
class DiyVector
{
public:
DiyVector()
{
arr = new T[1];
arrSize = 0;
index = 0;
capacity = 1;
}
~DiyVector()
{
delete[] arr;
}
T& at(unsigned int index) const
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
return arr[index];
}
}
unsigned int size() const
{
return arrSize;
}
void pushBack(const T& item)
{
if (arrSize == capacity)
{
arrTemp = new T[capacity += 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity++;
arr = arrTemp;
}
arr[arrSize] = item;
arrSize++;
}
void popBack()
{
if (arrSize == 0)
{
throw OutOfRange{};
}
else
{
arrSize--;
}
}
void erase(unsigned int index)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
arrTemp = new T[capacity -= 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity--;
arr = arrTemp;
}
}
void insert(unsigned int index, const T& item)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
}
class OutOfRange{};
private:
unsigned int arrSize;
unsigned int capacity;
unsigned int index;
T* arr;
T* arrTemp;
};
For starters this check in some member functions (for example including insert)
if (index >= arrSize || index < 0)
^^^^^^^^^^
does not make sense because the variable index declared as having the type unsigned int never can be negative. So you may exclude the second sub-condition of the if statement.
In the function pushBack in this loop
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
subsritute capacity for arrSize.
Also remove the statement
capacity++;
because capacity was already incremented in this statement
arrTemp = new T[capacity += 1];
Within the function insert change this code snippet
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
to
if ( arrSize <= index )
{
pushBack(item);
}
else
{
arr[index] = item;
}
And you may remove the data member
unsigned int index;
because it is not used.
Pay attention to that the member function erase is also incorrect. At least there is no need to reallocate the array and change its capacity. And again there are twice capacity is decremented.
arrTemp = new T[capacity -= 1];
//...
capacity--;
that is the function has the same defects as the function pushBack. And in the loop you are coping the erased element.
I just started to implement a basic vector container in C++. It is far from completion, but it looks like this:
using namespace std;
typedef unsigned long long int bigInt;
namespace stl2{
template<class T>
class vector{
private:
bigInt l;
bigInt cap;
T* arr;
public:
vector(){
cap = 0;
l = 0;
}
~vector(){
if (cap > 0) delete[] arr;
}
vector(bigInt size){
cap = size;
l = size;
arr = new T[size];
}
vector(bigInt size, const T& def) : vector(size){
for (bigInt i = 0; i < size; i++){
arr[i] = def;
}
}
bigInt size(){
return l;
}
bigInt length(){
return l;
}
bigInt capacity(){
return cap;
}
void resize(bigInt size){
if (size < cap) return;
l = size;
cap = size;
}
void push_back(const T& data){
// Check if vector is full
if (l == cap) {
//Copy all elements of this vector to another
if (cap == 0)
cap = 1;
else
cap *= 2;
T* temp = new T[cap];
for (int i = 0; i < l; i++){
temp[i] = arr[i];
}
delete[] arr;
arr = temp;
}
arr[l] = data;
l++;
}
//Operators
T& operator[](bigInt index){
if (index < cap)
return arr[index];
}
};
}
So I have a problem with the [] operator. I know that if the index < capacity, I can return arr[index].
But what do I return if the index is greater than or equal to the capacity? Since I am returning a reference to the element, I cannot return a value.
The std::vector throws an exception when using at() with an invalid index, you could do the same.
The operator[] of std::vector however does not perform bounds checking, using an invalid index is undefined behavior.
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;