template <class T>
class Vector {
int pos = 0;
int chunkSize;
T** p = new T*;
public:
Vector(int chunkSize = 1000) {
this->chunkSize = chunkSize;
p[0] = new T[chunkSize];
std::cout << &p[0] << std::endl;
}
~Vector() {
for (int i = 0; i < pos / chunkSize; i++) {
std::cout << &p[i] << std::endl;
delete [] p[i];
}
}
void pushBack(T val);
void display();
};
template<class T>
void Vector<T>::pushBack(T val) {
p[pos / chunkSize][pos % chunkSize] = val;
if (++pos % chunkSize == 0)
p[pos / chunkSize] = new T[chunkSize];
}
template<class T>
void Vector<T>::display() {
for (int i = 0; i < pos; i++)
std::cout << p[i / chunkSize][i % chunkSize] << " ";
std::cout << std::endl;
}
I was tinkering with some code today, and came up with the above. What I am trying to do is create something resembling a vector, by using fixed sized arrays, and just creating more as I need.
I usually program in Java, so memory management isn't my forte, and I am not sure that what I am doing is entirely okay. The vector is created fine, and I can add any number of values to it just fine. I can also display them, without issue, using the display function above. However, the destructor throws a SIGABRT when trying to delete any element, and that is why I am here, I don't know why I can't free memory I have allocated and have access to, although I guess one possibility is that I am writing and reading from memory I should not have access to. Those two cout statements print the same address for the 0th element, which I used to check that I was consistently looking at the same memory address.
Could someone explain to me either how to delete the elements properly, or why what I am doing is a huge mistake?
EDIT: The main class calls this code as follows.
int main() {
Vector<int> vec;
for (int i = 0; i < 1000000; i++)
vec.pushBack(i);
vec.display();
return 0;
}
The problem is that you only allocate space for one T* and store that in your p pointer. Once you push back chunksize elements, you write to p[1], which (since it past the end of the memory allocated for it) results in Undefined Behavior. Which includes running on apparently working for quite some time before it blows up.
You'll need to allocate additional space in the p array whenever you need to access additional elements there.
Related
I created a class that mimics the action of C++ vector by creating a dynamic array, I try to create a push back method for that class which first checks if the array is filled, if so it will:
1- Copy the contents of current array to a temporary array with the double size
2- Delete the old dynamic array
3- Create a new dynamic array with the double size of the old array (same size of temporary array)
4- Copy contents of the temporary array to the new dynamic array
the error is while I use the following code, I can only double the size of array once, then it throws to error:
HEAP[ConsoleApplication1.exe]: Invalid address specified to RtlValidateHeap( 016C0000, 016CDB98 )
ConsoleApplication1.exe has triggered a breakpoint.
#include <iostream>
using namespace std;
class SimpleVector {
private:
int* item; //pointer to the dynamic array (the vector)
int size;
int numElements;
public:
SimpleVector(int size) {
this->size = size;
this->numElements = 0;
this->item = new int[this->size];
}
SimpleVector():SimpleVector(10){}
void pushBack(int element) {
//check for overflow
if (numElements >= size) {
int newSize = size * 2;
int* temp = new int[newSize]; // temporary array with the double size to hold old array elements
for (int i = 0; i < numElements; i++) {
temp[i] = item[i];
}
delete[] item;
size = newSize;
//****ERROR IS IN THIS PART****
int* item = new int[size];
for (int i = 0; i < numElements; i++) {
item[i] = temp[i];
}
//****END OF THE PART CONTAINING ERROR****
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
else {
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
}
};
int main() {
SimpleVector v1(2);
v1.pushBack(1);
v1.pushBack(2);
v1.pushBack(3);
v1.pushBack(4);
v1.pushBack(5);
v1.pushBack(6);
v1.pushBack(7);
return 0;
}
This program pushs the first 4 items and then throws into error when trying to double the size form to 8
when I just replace that part containing error with:
item = temp
it works fine, but I can't understand why this happens.
Your code has several problems. I suggest you read about how to properly comply with Rule of Three/Five/Zero , which I'm not going to cover here. I only imagine this is for some nefarious academic purpose, so I will try to be brief, but please read the linked article.
That said, this:
int *item = new int[size];
for (int i = 0; i < numElements; i++)
{
item[i] = temp[i];
}
is pointless. This starts a cascade of bad actions that only gets worse as it rolls along.
You already have a member variable item. This code declares a local variable named item whose name hides the member item. Therefore the initialized value from the new operator is stored in the local, not the member.
That memory now pointed to by the local var item (not the member) is lost on exit of the function, since nothing but the local item ever points to it.
That additional allocation is pointless to begin with. You already made a new vector copy, pointed to by temp, and already copied all the legitimate items from memver-var item memory to temp memory. The code as-written leaks that temp allocation as well.
You destroy the member-var item memory, leaving the pointer now dangling, and any usage thereafter by dereference or eval invokes undefined behavior.
So, in summary, you make a valuable extended copy, leak it, make a worthless copy, leak it too, and end up leaving with a member variable that is no longer pointing at anything defined.
That entire function could look more like this:
void pushBack(int element)
{
// check for overflow
if (numElements >= size)
{
int newSize = size * 2;
int *temp = new int[newSize];
for (int i = 0; i < numElements; i++)
{
temp[i] = item[i];
}
delete[] item;
size = newSize;
item = temp;
}
item[numElements++] = element;
cout << "Added: " << element << endl;
cout << "Size is: " << size << endl;
}
I was trying to get used to the dynamic array in class to which I get the result to the output but get a core dump error.I get the output correct but at last of the output after compiling I get this core dump.
Output is
Enter the size of array: 4
Enter the numbers of array: 20
21
22
23
The element of the array is
20
21
22
23
munmap_chunk(): invalid pointer
Aborted (core dumped)
Here is the program I wrote:
class Array
{
private:
int *arr;
int size;
public:
Array(int sizes, int at[])
{
size = sizes;
arr = new int[size];
for (int i = 0; i < size; i++)
{
arr[i] = at[i];
}
}
Array()
{
size = 0;
}
~Array()
{
std::cout << "Destructor worked.";
delete[] arr;
}
void getarray()
{
std::cout << "Enter the size of array: ";
std::cin >> size;
setsize(size);
std::cout << "Enter the numbers of array: ";
for (int i = 0; i < size; i++)
{
std::cin >> arr[i];
}
}
void setsize(int sizes)
{
size = sizes;
}
void output(std::ostream& outs)
{
outs << "The element of the array is " << std::endl;
for (int i = 0; i < size; i++)
{
outs << arr[i] << std::endl;
}
}
};
I am still not good at dynamic array and I thought of using vectors. It will be great if anyone can show me what the problem with this problem is or any easier method for doing the same.
Assuming that your main() is somewhat like:
int main(void) {
Array foo; // or Array foo(bar, baz);
foo.getarray();
foo.output(std::cout);
}
The main problem here is that your constructor gets called before your getarray() method. And since you are already allocating memory inside your constructor,
void getarray() {
...
// Changing size, and iterating over it
...
}
is dangerous. If your newSize > size, the loop will try to access memory that does not belong to your program. If your newSize < size, it will not access all the elements.
How to overcome this?
Resize your array when you ask for size again.
Do not allocate memory inside the constructor, but allocate it inside getarr().
Do not resize your array inside getarray() at all, in which case you should not change your size.
All this really depends on the functionality you want to achieve. Say you want to have a fixed-sized array for the entire duration of your program, using a const qualifier with your size will help restrict un-authorized modifications.
If you want arrays which dynamically grow and shrink during your execution, you are better off using the std::vector container.
Hi i was creating a simple Vector Class for my studies.
Just to store Variable LONG
i kept everything simple. When i build nothing was return error/ warning.
Then after run the program, it works but the program crash.
Code Vector.h
class Vector{
public:
Vector();
void add(long i);
void getData();
private:
long *anArray;
long maxSize;
long position;
void reSize(int i);
};
Vector.cpp
Vector::Vector(){
maxSize = 2;
anArray = new long[maxSize];
position = 0;
}
void Vector::add(long i){
if(position==maxSize-1)
reSize(maxSize * 2);
anArray[position] = i;
position++;
}
void Vector::reSize(int i){
long *temp = new long[maxSize];
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
}
void Vector::getData(){
for(int i = 0; i<position; i++)
{
cout << "Element" << i+1 << " : " << anArray[i] << endl;
}
}
Main
int main()
{
Vector vecStore;
for(int i = 0; i < 1000; i++)
{
long a;
vecStore.add(a = i + 1);
}
cout << "GET DATA _________ :: " << endl;
vecStore.getData();
return 0;
}
The program wouldn't crash if the input data small(e.g. 10-20)
but when i change it to 100 or even bigger. the program sometime crash and sometime its not.
Did i make a mistake?
In
void Vector::add(long i){
if(position==maxSize-1)
reSize(maxSize * 2);
anArray[position] = i;
position++;
}
when position==maxSize-1, reSize is called to double the size of the array. Unfortunately, reSize is broken.
void Vector::reSize(int i){
long *temp = new long[maxSize];
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
}
The parameter i is never used. This should be the new size of the Vector, but instead the new array is allocated with the same maxSize as the previous array. maxSize goes unchanged.
Back in add, data is stored at position and position is increased by one. This means on the next add position is equal to maxSize, so the check to prevent overrunning the array,
if(position==maxSize-1)
will not do what you want and the program writes outside the bounds of the array. From there, position keeps getting larger, will never be equal to maxSize minus one, and writes even further out of bounds, not that it matters at that point. Undefined Behaviour has already been invoked, and Crom only knows what will happen. Maybe the program crashes, maybe the program crashes later, maybe it does something bizarre, and maybe it even chugs on looking like everything is working just fine.
You want something more along the lines of
void Vector::reSize(int newSize){ // note more descriptive name
long *temp = new long[newSize]; // using new size, not old size
for(int i =0; i<maxSize; i++)
{
temp[i] = anArray[i];
}
delete[] anArray;
anArray = temp;
maxSize = newSize; // store new size.
}
Vector also needs a destructor to clean up anArray, but in order to properly fix this error, here's a bit of recommended reading: What is The Rule of Three?
I have started implementing infinite array using templates in C++. Adding integers works well except one particular situation where I add two new items in one expression which required two resizes one after another (cf. below).
#include <iostream>
#include <cstddef>
#include <new>
#include <string.h>
template <typename T>
struct infinite_array {
infinite_array();
auto operator[](unsigned long long idx) -> T&;
auto size() const -> unsigned long long;
void resize(unsigned long long idx);
private:
T *data;
unsigned long long array_length;
};
template <typename T>
void infinite_array<T>::resize(unsigned long long idx)
{
std::cout << "Resize with idx " << idx << std::endl;
T* temp = new T[idx];
memset(temp, 0, sizeof(T) * idx);
for (int i = 0; i < array_length; ++i) {
temp[i] = data[i];
std::cout << temp[i] << " ";
}
std::cout << std::endl;
//std::copy(data, data+size(), temp);
delete [] data;
data = temp;
array_length = idx;
}
template <typename T>
infinite_array<T>::infinite_array()
{
data = NULL;
array_length = 0;
}
template <typename T>
auto infinite_array<T>::size() const -> unsigned long long {
//array_length = sizeof(data)/sizeof(T);
return array_length;
}
template <typename T>
auto infinite_array<T>::operator[](unsigned long long idx) -> T& {
//std::cout << "Accessing element at idx " << idx << std::endl;
if (idx+1 > size()) {
resize(idx+1);
}
return data[idx];
}
int main() {
infinite_array<int> ar;
for (int i = 0; i < 10; ++i) {
ar[i] = i;
}
// PROBLEM: ONLY ar[31] is initialized successfully to 10
ar[30] = ar[31] = 10;
for (int i = 0; i < ar.size(); ++i)
std::cout << ar[i] << ' ';
std::cout << std::endl;
return 0;
}
I'm afraid, there is no way to fix your problem, because you cannot control the order in which the calls to operator[] are made. And this is the problem:
Your compiler chooses to evaluate ar[30] first, which will resize your array and return a reference to one of its elements.
After that, ar[31] is evaluated, the array is resized again, another reference to one of the new arrays elements is returned. The old reference still points to the element in the old array (which is deleted!).
Finally, you compiler performs the assignment, assigning 10 to both elements. But since one of these elements lives in the old deleted array, you don't see it in the new array.
The simple truth is, that you must not chain calls to your operator[] like this, you can't work around the fact, that the compiler is allowed to perform the calls in any order.
Aside: It is generally a bad idea to resize any buffer on a one by one basis, the complexity of this is quadratic. Typical code uses increments of at least a factor 2. The precise factor is not so relevant, relevant is that you use a factor, because then you cut the complexity down to O(n). The value 2 is just a good tradeoff between space and time overhead.
Typically, you will not want to have your accessor methods (at() or operator[]) resize the array as it would violate separation of concerns (each function should do 1 thing - having it resize would require it to do 2).
The way the standard library implements std::vector: If you use at() and supply an address out of bounds, it throws an exception (if you use operator[], it is UB).
The problem you are running into with
ar[30] = ar[31] = 10;
If the size of the array must be resized, then both calls are going to have to resize it. It is very similar to what happens with i = i++ + ++i; (which is also UB). When you resize to size 31, you have a temp buffer and set the value of the new element to 10. When you resize to 32, you have a (different) temp buffer and set the value of the new element to 10. When the later one returns, it does not have the value of the former, so only 1 is written. To fix it, separate your operations.
Let's say I have a dynamic array:
int* p;
ifstream inFile("pop.txt");
int x;
while (inFile >> x)
{
// ????
}
How do I resize p so I am able to to fit x in as like an array. I don't want to use a vector or static array as I am trying to learn the language. I need to use pointers because I don't know the initial size. Any attempt is appreciated.
The simplest answer is that you should use higher level components than raw arrays and raw memory for the reading. That way the library will handle this for you. A simple way of reading a set of numbers into an application (without error handling) could be done with this simple code:
std::vector<int> data;
std::copy(std::istream_iterator<int>(inFile), std::istream_iterator<int>(),
std::back_inserter(data));
The code creates a couple of input iterators out of the stream to read int values, and uses a back_inserter iterator that will push_back onto the vector. The vector itself will manage growing the memory buffer as needed.
If you want to do this manually you can, you just need to allocate a larger chunk of memory, copy the first N elements from the old buffer, release the old buffer and continue reading until the larger buffer gets filled, at which point you follow the same procedure: allocate, copy, deallocate old, continue inserting.
You can't resize it. All you can do is allocate a new bigger array, copy everything over from the old array to the new array, then free the old array.
For instance (untested code)
int array_size = 10;
int* array = new int[array_size];
int array_in_use = 0;
int x;
while (in >> x)
{
if (array_in_use == array_size)
{
int* new_array = new int[2*array_size];
for (int i = 0; i < array_size; ++i)
new_array[i] = array[i];
delete[] array;
array = new_array;
array_size *= 2;
}
array[array_in_use++] = x;
}
It's tedious, and I'm not convinced it's a good thing for a beginner to be doing. You'd learn more useful stuff if you learned how to use vectors properly.
You could always use realloc(). It's a part of the C Standard Library, and the C Standard Library is a part of the C++ Standard Library. No need for tedious news and deletes.
#include <cstdlib>
#include <iostream>
#include <fstream>
int main(void)
{
int* array = nullptr;
unsigned int array_size = 0;
std::ifstream input("pop.txt");
for(int x; input >> x;)
{
++array_size;
int* array_failsafe = array;
array = static_cast<int*>(realloc(array, sizeof(x) * array_size));
if(array == nullptr)
{
std::cerr << "realloc() failed!" << std::endl;
free(array_failsafe);
return EXIT_FAILURE;
}
array[array_size-1] = x;
}
for(unsigned int i = 0; i < array_size; ++i)
{
std::cout << "array[" << i << "] = " << array[i] << std::endl;
}
free(array); // Don't forget!
return EXIT_SUCCESS;
}