I am trying create my own vector, I am at the beginning, and when compile e execute the code, i get "Program not responding". This is the code:
struct X
{
X(){};
~X(){};
int v1, v2, v3;
};
template<typename T>
class Vector
{
public:
// constructors
Vector();
Vector(unsigned s);
virtual ~Vector();
// overloaded operators
T operator[](unsigned index);
// others
void clear();
void add(T value);
unsigned getSize();
bool isEmpty();
private:
// pointer to first item of memory block
T* first;
unsigned size;
};
template<typename T>
Vector<T>::Vector()
{
first = NULL;
size = 0;
}
template<typename T>
Vector<T>::Vector(unsigned s)
{
size = s;
first = new T[s];
};
template<typename T>
Vector<T>::~Vector()
{
clear();
}
template<typename T>
void Vector<T>::clear()
{
for(unsigned i = size ; i > 0 ; i--)
delete &first[i];
first = NULL;
}
template<typename T>
void Vector<T>::add(T value)
{
T* temp = new T[size + 1]; // error happens here
// copy data to new location
for(unsigned i = 0 ; i < size ; i++)
temp[i] = first[i];
// delete older data
clear();
// add the new value in last index
temp[size + 1] = value;
// update the pointer
first = temp;
size++;
}
template<typename T>
T Vector<T>::operator[](unsigned index)
{
return first[index];
}
template<typename T>
unsigned Vector<T>::getSize()
{
return size;
}
template<typename T>
bool Vector<T>::isEmpty()
{
return first == NULL;
}
int main(int argc, char* args[])
{
Vector<X> anything;
X thing;
anything.add(thing);
anything.add(thing);
anything.add(thing); // if remove this line, program work fine.
}
As I commented, error happens in T* temp = new T[size + 1];.
If i define the value of v1, v2, v3 of X class, e.g. X() : v1(0), v2(0), v3(0) { }, the program works correctly.
If i change the type, e.g., Vector of int, he works perfectly.
If put X class in std::vector, work fine too.
Other comments are also accepted.
Can someone helpme?
Your description of the problem is incredibly vague, but I can point out problems with your code:
No vector copy constructor (causes double-deletes and crashes)
No vector copy assignment (causes double-deletes and crashes)
clear is incorrectly calling delete (causes crashes and corruption) (you should match your single new of an array with a single delete of the array. Don't loop over elements.
add is writing past the end of the array (causes crashes and corruption)
add is not exception safe
You have to fix at least the first four. The third and fourth are probably the causes of your hang.
You have a buffer overflow occurring.
T* temp = new T[size + 1]; // When size is 0, you allocate 1 space.
You then assign to the temp array, but in location temp[1], which isn't a valid location because your array has only 1 element. This is undefined behavior, and that this point, your program is free to continue however it chooses. In this case, it seems to loop indefinitely.
// add the new value in last index
temp[size + 1] = value; // When size is zero, your array is length '1', but
// you are accessing temp[1] which is outside the
// bounds of your allocated memory.
Related
Learning from Accelerated C++: Practical Programming by Example, in chapter 11, there was an implementation (only with basic features) of vector container from STL. After that was an exercise for implementing erase function just as std::vector does. What I have tried:
#include <memory>
template<class T>
class Vec{
private:
T *data;
T *avail;
T *limit;
std::allocator<T> alloc;
...
public:
explicit Vec(size_t n, const T &val = T())
{
create(n, val);
}
T *const begin()
{
return data;
}
T *const end()
{
return avail;
}
T *erase(T* const pos);
...
};
template <class T>
void Vec<T>::create(size_t n, const T &val)
{
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}
// here I am trying to implement the erase function with 3 pointers (data, avail, limit)
template<class T>
T* Vec<T>::erase(T *const i)
{
if(i==end())
{
return end();
}
else if(i >= begin() && i < end())
{
size_t member = i-data;
size_t size = limit-data;
T* new_data = alloc.allocate(size);
std::uninitialized_copy(data, i, new_data);
T* new_avail = std::uninitialized_copy(i+1, avail, i);
data = new_data;
avail = new_avail;
limit = data + size;
return &data[member];
}
else
{
return 0;
}
}
Now If I want to check, if that function works correctly:
#include "vec.hpp"
int main()
{
Vec<int> v(5, 2);
if (v.erase(v.begin()+2))
{
for (int i:v)
{
cout << i << endl;
}
}
}
I get
...
0
0
0
0
Segmentation fault
I have somehow made infinity allocation-loop, but I have no idea how. Anyway, How can I make the erase function (or in another words, how to shift elements after the erased one to left), via std::uninitialized_copy?
EDIT:
the whole class definition is there:
https://www.codepile.net/pile/rLmz8wRq
Here you create new storage for vector:
T* new_data = alloc.allocate(size);
and here you write to array pointed by argument, which (supposedly) points to location on old storage. new_avail would point to old storage.
T* new_avail = std::uninitialized_copy(i+1, avail, i);
^ that's destination
^ that's source
Then you even leak memory:
data = new_data; // old storage pointed by data is lost along with the "tail" of array
After this vector state is completely broken, pointer arithmetic go to undefined area:
avail = new_avail; // avail points to old storage, data points to new one.
// (data < avail) no longer guaranteed to be true
Because in all likelihood data would be greater than avail, you don't get an infinite loop, you may get a very long one. OR may not. Attempt to iterate through vector after this "erase" amounts to Undefined Behavior.
I'm creating a stack class as an exercise trying to learn some c++ concepts (initializer lists, memory management and templates here). I've run into something that I can't get my head around.
In function void Stack::push(const T& item), if I uncomment the delete [] data; line, my code runs well when the template argument is for example int or char. But with std::string, I get weird memory errors.
My thinking here is that I need a bigger array -> arrays can't be resized -> I create a new one -> I deallocate the memory I needed for the one that's soon to be not needed -> I make the existing pointer point to a new memory address where I create the bigger array.
Now, when I comment the delete line, the code runs well even with std::string, but I can't see why I can't do the delete operation safely with all types.
Any insights will be appreciated.
#include <iostream>
#include <stdio.h>
#include <memory.h>
template<class T>
class Stack
{
T* data;
int sz;
public:
//Stack(){sz=0;}
Stack(const std::initializer_list<T>&);
~Stack();
void push(const T&);
T& pop();
void show() const;
};
template<class T>
Stack<T>::Stack(const std::initializer_list<T> &list)
{
sz=0;
data = new T[list.size()];
for (auto i : list) {
data[sz] = i;
++sz;
}
std::cout<< "Created with sz: "<< sz<<std::endl;
}
template<class T>
Stack<T>::~Stack()
{
delete [] data;
}
template<class T>
void Stack<T>::push(const T& item) {
std::cout<<"push "<<item<<std::endl;
T* arr = new T[sz];
memcpy(arr, data, sz*sizeof(T));
//delete [] data;
data = new T[sz + 1];
memcpy(data, arr, sz*sizeof(T));
++sz;
data[sz - 1] = item;
std::cout<<"new size: "<<sz<<", bytes: "<<sz*sizeof(T)<<std::endl;
}
template<class T>
T& Stack<T>::pop()
{
if(sz > 0) {
std::cout<<"pop "<<data[sz-1]<<std::endl;
std::cout<<"new size: "<<sz-1<<std::endl;
return data[--sz];
}
else
return data[0];
}
template<class T>
void Stack<T>::show() const
{
for (int i=0; i<sz; i++) {
std::cout<<data[i]<<" ";
}
std::cout<<std::endl;
}
int main(){
Stack<int> s = {1,2,3,4,5,6,7,8,9,10,11};
s.show();
s.push(12);
s.push(13);
s.push(14);
s.pop();
s.pop();
s.push(15);
s.push(16);
s.show();
Stack<std::string> d = {"one","two","three"};
d.show();
d.pop();
d.push("four");
d.show();
return 0;
}
Don't use memcpy to copy objects, that will copy the bits alright, but for some object a bit-wise copy is not correct as the copy constructor (or copy assignment operator) Will not be used.
A good and simple example is if you have a stack of std::string objects. When you do a bit-wise copy (with memcpy) the contents of the std::string objects are copied, but that basically is just a pointer and a size. When you do a bit-wise copy then you will have two std::string objects referencing the same memory. Destroying one of those object will lead to the other having a stray pointer to some memory (that used to contain the string) that no longer is owned by your program.
To solve this use std::copy instead to copy the objects, it will do the right thing.
Unrelated to your problem, but your push function does a copy that it doesn't need:
T* arr = new T[sz];
memcpy(arr, data, sz*sizeof(T));
This is simply not needed, instead do something like
T* oldData = data;
data = new T[sz + 1];
// Copy from old array to new
std::copy(oldData, oldData + sz, data);
delete[] oldData;
So, I am trying to run the class below with
int x = 5;
mystack<int> st;
st.push(x);
However, I keep getting build failure, I can't seem to figure out why.
#ifndef MYSTACK_H
#define MYSTACK_H
#include <vector>
using namespace std;
template<typename T>
class mystack {
private:
vector<T> data;
int size = 0;
public:
void push(T const &);
};
template<typename T>
void mystack<T>::push(T const & elem) {
data[size] = elem;
size++;
}
RUN FAILED ( exit value -1, 073, 741, 819, total time: 1s)
Also completely separate question, how do I throw an underflow? I tried
throw underflow_error();
Initially your vector<T> data is empty. Its size() is 0. You cannot access to any of its elements. That might be the reason of getting an error.
Try using this code:
template<typename T>
void mystack<T>::push(T const & elem) {
data.push_back(elem);
}
It actually will increase you data.size() by 1 every time you push an element.
Don't want to use any vector STL
Wonder you are having vector<T> in code, looks like STL. You can use plain dynamic arrays as an alternative or even static ones.
template<typename T>
class mystack {
private:
T* data;
int size = 0;
int maxSize;
public:
mystack(int maxSize) :maxSize(maxSize) { data = new data[maxSize]; }
~mystack() { delete[] data; }
void push(T const &);
};
template<typename T>
void mystack<T>::push(T const & elem) {
// here you may check if you already reached the maxSize;
data[size++] = elem;
}
Note that in order to fully simulate STL vector behaviour you should consider reallocating the array each time you have size = allocateSize. STL vector makes this every time the number of elements hits the power of 2, it doubles its size.
I propose you to use std::stack instead of implement your own stack using std::vector. If you don't want use STL at all, your should control memory allocation and deletion by yourself. In your example, in the line data[size] = elem;, you assign value to not allocated memory, it is your problem. You can fix it that way, if you don't want to use push_back() method:
template<typename T>
void mystack<T>::push(T const & elem) {
size += 1;
data.resize(size);
data[size] = elem;
}
About std::underflow_error. It designed for arithmetic underflow errors. Anyway, this class has constructor where your should put string, so you need change throw underflow_error(); to throw underflow_error("Error message");.
Using C++, I am trying to create an array that holds pointers to objects I'm storing. But when the array is full, I want to expand the array.
the easy option is to allocate a new array with bigger size, then copy the elements to it, this is quite inefficient, and I thought of another way I want to try to do it:
create array of fixed size X
When full, create a new array, and make the end of the first array point to the start of the first element
Repeat as long as needed
What methods can I use to do that? I thought of one way to do it, but it seems very hacky:
declare all my new array as pointers to object pointer, then reinterprit_cast the filled elements to object pointer.
Note: I know I can use Vector, but I am instructed not to use std library.
Kind Regards,
There are some good answers in the comments already. I just want to provide a way to achieve exactly the behavior you described.
Since the elements of the array are pointers as well, you can define a union as the element of your array like this:
template<typename T>
union Cell
{
T* pElm;
Cell* pNext;//A fixed size array of Cells
}
And then build your array on top of it. For example:
template<typename T>
class SpecialArray
{
public:
//the next pointer is included
static const size_t ARRAY_LEN = 1000;// For example
using Pointer = T*;
using Segment = Cell<T>[ARRAY_LEN];
protected:
Segment* pFirst;
size_t mSize;
public:
SpecialArray()
:pFirst(nullptr),mSize(0){}
SpecialArray(SpecialArray&&){}
~SpecialArray(){}
Pointer& operator[](size_t index)
{
Segment* seg = pFirst;
size_t offest = 0;
//Search logic...
return seg[offest]->pElm;
}
const Pointer& operator[](size_t index) const;
};
Using C++, I am trying to create an array that holds pointers to
objects I'm storing. But when the array is full, I want to expand the
array.
With C++ templates and C primitives we can improvise a simple vector like below. And the grow buffer strategy is to double the size when the threshold is met.
#include <iostream>
#include <stdlib.h>
template <typename T>
class MyVector
{
public:
MyVector() : m_count(0), m_size(0), m_buffer(0)
{
m_size = bufInitSize;
m_buffer = (T*)malloc(sizeof(T) * bufInitSize);
}
~MyVector()
{
if (m_buffer)
free(m_buffer);
}
void add(const T& p)
{
if (m_count + 1 >= m_size)
{
m_size *= 2;
m_buffer = (T*)realloc(m_buffer, sizeof(T) * m_size);
}
m_buffer[m_count ++ ] = p;
}
T& operator[](int idx)
{
return m_buffer[idx];
}
private:
static const int bufInitSize = 1024;
T* m_buffer;
int m_count;
int m_size;
};
void main()
{
// using MyVector
MyVector<int*> vctOfIntPtr;
int n = 100;
vctOfIntPtr.add(&n);
int* pN = vctOfIntPtr[0];
std::cout << *pN;
}
I have the following class and code:
template <class T>
class HashTable {
struct Pair{
T element;
int key;
Pair(T element, int Key) : element(element), key(key) {};
};
int table_size;
int counter;
List<Pair> (*elements);
void changeTableSize(int newSize){
List<Pair> *temp = new List<Pair>[newSize];
for (int i = 0; i < table_size; i++){
for (typename List<Pair>::Iterator j = elements[i].begin(); j != elements[i].end(); j++){
Pair p = *j;
temp[p.key % newSize].insert(Pair(p.element, p.key));
}
}
delete[] elements;
elements = temp;
table_size = newSize;
}
public:
HashTable() : table_size(100), counter(0){
elements = new List<Pair>[table_size];
};
void insert(T data, int key){
if (member(key)){
throw ElementAlreadyExists();
}
elements[key % table_size].insert(Pair (data, key));
counter++;
if (counter == table_size){
changeTableSize(table_size*2);
}
};
When I call changeTableSize() the first time, everything is fine. When I call it the second time my program crashes saying "warning: HEAP: Free Heap block 006618C0 modified at 006618D4 after it was freed" right after the allocation for temp. What can cause this?
If originalSize > table_size then you are performing an illegal memory access in the inner 'for' loop.
Remove the 'originalSize' argument that you are passing to the function.
Use the class variable 'table_size' instead, and update it to the new size before you return.
Also, make sure that class Pair has a copy-constructor properly defined and implemented:
Pair(const Pair& pair)
{
// For each variable x of pair, that points to dynamically-allocated memory:
// this->x = new ...
// memcpy(this->x,pair.x,...)
// For each variable y of pair, that doesn't point to dynamically-allocated memory:
// this->y = pair.y
}
Otherwise, you might have two different instances of class Pair with internal variables pointing to the same dynamically-allocated memory. And when one instance is destroyed, the internal variables of the other instance will point to an already-freed memory.