After declaring a default constructor for this templated program I am working on:
template<typename T>
Set<T>::Set()
: size(0), capacity(8) {
//allocate new array
items = new T[capacity];
}
I have a relatively inconspicuous function contains that tests for whether or not items contains a specific item in it.
template<typename T>
bool Set<T>::contains(const T& item) const {
for (int i = 0; i < size; i++) {
if (this->items[i] == item)
return true;
}
return false;
}
It works fine when I call it in certain locations such as this function that reads through items and only adds an item if there is no other copy (part of our assignment specifications):
template<typename T>
void Set<T>::add(const T& item) {
if (this->contains(item) == 0) {
grow();
items[size++] = item;
}
}
But when I call it when attempting to overload the operator ==, I get the error in the title when I run it through DRMemory
template<typename T>
bool Set<T>::operator==(const Set<T>& other) const {
int count = 0;
for (int i = 0; i < size; i++) {
if (this->contains(other.items[i])) {
count++;
}
}
if (count == size)
return true;
return false;
}
for (int i = 0; i < size; i++) {
if (this->contains(other.items[i])) {
count++;
}
}
size should be other.size. Otherwise other.items[i] in the loop may be out-of-bounds if size > other.size.
Similarly size in the later check needs to be other.size as well.
On the other hand, you need to add a test for size == other.size anyway to make sure that the sets are really equal. If you put that at the beginning, it won't matter whether you use size or other.size later.
Btw. instead of using count to count the identical elements, you can just return false as soon as one .contains fails.
Related
Sequel to: array wrapper corrupts stack
The project:
I am working on a std::vector replacement.
The error:
I get a heap corruption error whenever I attempt to delete a temporary array I am creating in order to store the copied elements of another array that I delete in order to reallocate it when my array gets resized. (It seems that if I try to assign one array to another, I actually end up assigning the pointer to the array to the other array instead of copying the elements. Truly crazy stuff).
I read online that this error may actually come from the part where I actually interact with the array, but the error only pops out when I attempt to delete it.
Where I interact with the array is the function _tempcpy. I pass a pointer to a source and destination array and copy each element from the source to the destination. I struggled a bit with making sure that the array would start from 0 and not 1 and in the process I messed a bit too much with the element_count member, so it may be that i am somehow writing outside of bounds and I have stared so much at the code I can't see the issue.
The code:
template<class T> class dyn_arr
{
public:
dyn_arr(void)
{
this->array = {};
this->element_count = {};
}
~dyn_arr(void)
{
this->dealloc();
}
bool alloc(unsigned int element_count)
{
if (0 == element_count)
{
element_count = 1;
}
if (this->array != nullptr)
{
T* temp = new T[this->element_count];
if (false == this->_tempcpy(&this->array, &temp, this->element_count))
{
return false;
}
delete[] this->array;
this->array = new T[this->element_count];
if (false == this->_tempcpy(&temp, &this->array, this->element_count))
{
return false;
}
delete[] temp;
if (nullptr != this->array)
{
return true;
}
}
else
{
this->array = new T[this->element_count];
if (nullptr != this->array)
{
return true;
}
}
return false;
}
bool dealloc(void)
{
if (nullptr == this->array)
{
return false;
}
delete[] this->array;
return true;
}
bool add(T Object)
{
if (0 == Object)
{
return false;
}
if (true == this->alloc(this->element_count))
{
this->array[this->element_count] = Object;
++this->element_count;
return true;
}
return false;
}
T get(unsigned int index)
{
if (index > this->element_count)
{
return T{};
}
return this->array[index];
}
unsigned int get_count(void)
{
return this->element_count;
}
private:
bool _tempcpy(T** src, T** dest, unsigned int count)
{
if ((nullptr == src) || (nullptr == dest) || (0 == count))
{
return false;
}
for (unsigned int i = 0; i < count; ++i)
{
*dest[i] = *src[i];
}
return true;
}
T* array;
unsigned int element_count;
};
int main()
{
dyn_arr<int> pNr = {};
pNr.add(1);
pNr.add(2);
pNr.add(3);
for (int i = 0; i < pNr.get_count(); ++i)
{
printf("%d\n", pNr.get(i));
}
getchar();
return 0;
}
In your alloc function there lie a few problems, such as:
if (0 == element_count)
{
element_count = 1;
}
is unnecessary. Instead, you can just do a +1 where necessary which is almost everywhere except the temp dynamic array.
bool alloc(...)
{
this->array = new T[this->element_count];
//...
else
{
this->array = new T[this->element_count];
}
}
should be
this->array = new T[this->element_count + 1];
//...
else
{
this->array = new T[this->element_count + 1];
}
this will fix the problems with allocation. That leaves us with _tempcpy() which fails because instead of trying to get the next element of the underlying array, it tries to do that with the double ptr itself. Read about operator precedence rules. Fixed version:
bool _tempcpy(T** src, T** dest, unsigned int count)
{
//....
for (unsigned int i = 0; i < count; ++i)
{
(*dest)[i] = (*src)[i];
}
//....
}
However, I am unsure as to why double ptr is needed in this function in the first place. Just use single pointers. Also dest should be const as it is not changing in this function. It gives the reader of the function a clear idea of which parameters will change inside the function and which will not:
bool _tempcpy(T* src, const T* dest, unsigned int count) {...}
same could be applied to other parts of the class.
Additionally, in C++
dyn_arr(void)
We don't do this. There's no need to explicitly write void. According to the C++ standard:
8.3.5 Functions [dcl.fct]
...
A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
So I am trying to implement this method to know if an integer occurs twice consecutively in my stack array. This integer is taken as a parameter and I want to know if it happens twice consecutively. Unfortunately, my method always returns false, do you know why?
template<class T>
bool stack<T>::isConsecutive( const T & data ) const{
bool flag=false;
for (size_t i = 0; i < _top; i++) {
if(data==elements[i] && elements[i]==elements[i+1]){
flag=true;
}
else {
flag=false;
}
}
return flag;
}
try this
template<class T>
bool stack<T>::isConsecutive( const T & data ) const{
bool flag=false;
for (size_t i = 0; i < _top-1; i++) {
if(data==elements[i] && elements[i]==elements[i+1]){
return true;
}
}
return flag;
}
this will work i guess .
I have an array-based list class called Alist with the following remove function. Note that everything is done with respect to the fence, so removing item is done to the right of the fence. This means if I want to delete a specific item, I should set the value of fence to the index of that item, then call the remove function.
template <class Elem>
bool AList<Elem>::remove(Elem& item)
{
if (rightLength() == 0) return false;
it = listArray[fence + 1]; // Copy element
for (int i = fence + 1; i < listSize; i++)
{
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
Now I have created a list of majors and have implemented the following function:
void removeMajor(AList<Major> &t, Major &m)
{
if (t.find(m))
{
t.setPos() // ??? Not sure
t.remove(m); //inserting major
}
}
My removeMajor function is wrong, I don't know how to set the position of the fence to the element I want to delete. Could anyone help me?
Side Note: (setPos() function is as follows)
bool setPos(int pos)
{
if ((pos >= 0) && (pos < listSize))
fence = pos;
return (pos >= 0) && (pos < listSize);
}
Help would be very much appreciated!
I would suggest creating a function, find:
template <class Elem>
int AList<Elem>::find(Elem& item)
{
for (int i = fence + 1; i <= listSize; i++)
{
if ( listArray[i] == item )
{
return i;
}
}
return -1;
}
and then, using it in the implementation of remove.
template <class Elem>
bool AList<Elem>::remove(Elem& item)
{
int index = this->find(item);
if ( index == -1 )
{
return false;
}
for (int i = index; i <= listSize; i++)
{
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
}
In both the functions, I am using i <= listSize since you have the "fence" item.
Please note that if there are multiple items that are equal to item, the function will remove only the first one. You'll have to make sure that rest of your code does not have a problem with that behavior.
I have written a class Stack whose both sides are used, i.e. two stacks in one.
One from [0] until [someplace - 1] and one from [capacity-1] until [someplace +1].
Everything is fine but I have some problems with doubling the memory when my array is full.
My code works for doubling at first, but when it needs to double some more it gives me some weird error.
_ctrlvalidHeappointer
critical section error
This is my code. There is some explanation in the code too. When I push too many element in the stack it fails.
string firstname = "asasasasasaasasasasassasasasaasas";
string secondname= "asasdasfregeasasasasasgergergererg";
for (int i = 0; i < firstname.length(); i++)
{
a.push_at_first(firstname.at(i));
}
for (int i = 0; i < secondname.length(); i++)
{
a.push_from_end(secondname.at(i));
}
It is my class
using namespace std;
template <class T>
class Stack{
public:
Stack();
~Stack();
Stack(const Stack<T>& ob);
void double_size();
void push_at_first(T mydata);
void push_from_end(T mydata);
T & operator = (Stack<T> ob);
private:
int top;
int top2;
T * stack;
int capacity;
};
template <class T>
T& Stack<T>::operator = (Stack<T> ob)
{
if(capacity == ob.capacity){
top = ob.top;
top2 = ob.top2;
for (int i = 0; i < capacity; i++)
{
stack[i] = ob.stack[i];
}
return *this;}
else
{
capacity = ob.capacity;
stack = new T[capacity];
for (int i = 0; i < capacity; i++)
{
stack[i] = ob.stack[i];
}
}
}
template <class T>
Stack<T>::Stack (const Stack<T>& ob) :capacity(ob.capacity)
{
stack = new T[capacity];
top = ob.top;
top2=ob.top2;
for (int i = 0; i < capacity; i++)
{
stack[i] = ob.stack[i];
}
}
template <class T>
Stack<T>::~Stack()
{
delete [] stack;
}
template <class T>
Stack<T>::Stack()
{
capacity = 17;
top = 0;
top2 = capacity-1;
stack = new T[capacity];
}
template <class T>
void Stack<T>::push_at_first(T mydata)
{
if ( (top + 1) == (top2 -1) ) // 1 : because I want to Be a Empty Space between Two Stack so i can tell the difference
double_size();
stack[++top] = mydata;
}
template <class T>
void Stack<T>::push_from_end(T mydata)
{
if( (top + 1) == (top2 -1) ) // 1 : because I want to Be a Empty Space between Two Stack so i can tell the difference
double_size();
stack[--top2] = mydata;
}
template <class T>
void Stack<T>::double_size()
{
Stack<T> temp(*this);
capacity *= 2;
stack = new T[capacity];
top = temp.top;
top2 = capacity - (temp.capacity - temp.top2);// capacity - number of data in stack of temp ;
// if we have something in first stack then copy 0 to top elements of temp.stack to stack
if(top > 0)
{
for (int i = 0; i <= top ; i++)
{
stack[i] = temp.stack[i];
}
}
// There is Something Wrong Down here ! i can't figure out what !
if(top2 < capacity - 1)
{
for (int i = capacity-1; i >= top2; i--)
{
stack[i] = temp.stack[i-(temp.capacity)];
}
}
}
I see several problems.
You're missing a copy constructor and assignment operator.
You're explicitly calling the destructors of the elements.
This will lead to trouble when delete does it again, as it does automatically.
You're not allocating the proper amount of memory for temp.stack in double_size. Even though you have access to the private members of temp, you should let it manage itself (see copy constructor above).
(BTW: that variable is unnecessary - just copy from your old memory block to a new one, then delete the old block and assign the new block pointer to stack.)
There may also be some problems with the indexing in double_size, but you should fix those three problems first.
I have a technical problem and it's really confusing me. I apologise in advance because I may not be giving the relevant details; I don't yet why it's going wrong and it would be excessive to include all the code I'm working with.
I'm working with a large program that uses the C++ STL. I'm moving this code to a very sensitive environment without a standard clib nor STL implementaton; it will redefine malloc/free/new/delete etc... For that, I need to replace the std:: parts with my own simplified implementations. I've started with std::vector. Right now it's running in the standard ecosystem so it's the GNU libc and STL. The only thing that's changed is this vector class.
When I execute the program with the replaced class, it segfaults. I've put this through GDB and found that the program will request an object from the vector using the subscript operator. When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class.
I'm really not sure at all what the problem is here. I would love to provide additional details, but I'm not sure what more I can give. I can only assume something is wrong with my vector implementation because nothing else in the program has been changed. Maybe there's something obvious that I'm doing wrong here that I'm not seeing at all.
I'm using: g++ (GCC) 4.4.5 20110214 (Red Hat 4.4.5-6)
I'd really appreciate any feedback/advice!
#ifndef _MYSTL_VECTOR_H_
#define _MYSTL_VECTOR_H_
#include <stdlib.h>
#include <assert.h>
typedef unsigned int uint;
namespace mystl
{
/******************
VECTOR
********************/
template <typename T>
class vector
{
private:
uint _size;
uint _reserved;
T *storage;
void init_vector(uint reserve)
{
if (reserve == 0)
{
_reserved = 0;
return;
}
storage = (T*)malloc(sizeof(T)*reserve);
assert(storage);
_reserved = reserve;
}
public:
vector()
{
// std::cerr << "default constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
}
vector(const vector<T> &other)
{
// std::cerr << "copy constructor " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(other.size());
_size = other.size();
for (uint i=0; i<other.size(); i++)
{
storage[i] = T(other[i]);
}
}
vector(uint init_num, const T& init_value)
{
// std::cerr << "special constructor1 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
for (size_t i=0; i<init_num; i++)
{
push_back(init_value);
}
}
vector(uint init_num)
{
// std::cerr << "special constructor2 " << this << std::endl;
storage = NULL;
_size = 0;
_reserved = 0;
init_vector(init_num);
}
void reserve(uint new_size)
{
if (new_size > _reserved)
{
storage = (T*)realloc(storage, sizeof(T)*new_size);
assert(storage);
_reserved = new_size;
}
}
void push_back(const T &item)
{
if (_size >= _reserved)
{
if (_reserved == 0) _reserved=1;
reserve(_reserved*2);
}
storage[_size] = T(item);
_size++;
}
uint size() const
{
return _size;
}
~vector()
{
if (_reserved)
{
free(storage);
storage = NULL;
_reserved = 0;
_size = 0;
}
}
// this is for read only
const T& operator[] (unsigned i) const
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
T& operator[] (unsigned i)
{
// do bounds check...
if (i >= _size || i < 0)
{
assert(false);
}
return storage[i];
}
// overload = operator
const vector<T>& operator= (const vector<T>& x)
{
// check for self
if (this != &x)
{
_reserved = 0;
_size = 0;
storage = NULL;
init_vector( x.size() );
for(uint i=0; i<x.size(); i++)
{
storage[i] = T(x[i]);
}
_size = x.size();
}
return *this;
}
uint begin() const
{
return 0;
}
void insert(uint pos, const T& value)
{
push_back(value);
if (size() == 1)
{
return;
}
for (size_t i=size()-2; i>=pos&& i>=0 ; i--)
{
storage[i+1] = storage[i];
}
storage[pos] = value;
}
void erase(uint erase_index)
{
if (erase_index >= _size)
{
return;
}
//scoot everyone down by one
for (uint i=erase_index; i<_size; i++)
{
storage[i] = storage[i+1];
}
_size--;
}
void erase(uint start, uint end)
{
if (start > end)
{
assert(false);
}
if (end > _size)
end = _size;
for (uint i=start; i<end; i++)
{
erase(start);
}
assert(false);
}
void clear()
{
erase(0,_size);
}
bool empty() const
{
return _size == 0;
}
}; //class vector
}
#endif // _MYSTL_VECTOR_H_
Wow!
Your assignment operator also leaks memory.
Becuause you are using malloc/release the constructor to your type T will will not be called and thus you can not use your vector for anything except the most trivial of objects.
Edit:
I am bit bored this morning: Try this
#include <stdlib.h> // For NULL
#include <new> // Because you need placement new
// Because you are avoiding std::
// An implementation of swap
template<typename T>
void swap(T& lhs,T& rhs)
{
T tmp = lhs;
lhs = rhs;
rhs = tmp;
}
template <typename T>
class vector
{
private:
unsigned int dataSize;
unsigned int reserved;
T* data;
public:
~vector()
{
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Because we use placement new we must explicitly destroy all members.
data[loop].~T();
}
free(data);
}
vector()
: dataSize(0)
, reserved(10)
, data(NULL)
{
reserve(reserved);
}
vector(const vector<T> &other)
: dataSize(0)
, reserved(other.dataSize)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// Because we are using malloc/free
// We need to use placement new to add items to the data
// This way they are constructed in place
new (&data[loop]) T(other.data[loop]);
}
}
vector(unsigned int init_num)
: dataSize(0)
, reserved(init_num)
, data(NULL)
{
reserve(reserved);
dataSize = reserved;
for(unsigned int loop;loop < dataSize;++loop)
{
// See above
new (&data[loop]) T();
}
}
const vector<T>& operator= (vector<T> x)
{
// use copy and swap idiom.
// Note the pass by value to initiate the copy
swap(dataSize, x.dataSize);
swap(reserved, x.rserved);
swap(data, x.data);
return *this;
}
void reserve(unsigned int new_size)
{
if (new_size < reserved)
{ return;
}
T* newData = (T*)malloc(sizeof(T) * new_size);
if (!newData)
{ throw int(2);
}
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Use placement new to copy the data
new (&newData[loop]) T(data[loop]);
}
swap(data, newData);
reserved = new_size;
for(unsigned int loop = 0; loop < dataSize; ++loop)
{
// Call the destructor on old data before freeing the container.
// Remember we just did a swap.
newData[loop].~T();
}
free(newData);
}
void push_back(const T &item)
{
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Place the item in the container
new (&data[dataSize++]) T(item);
}
unsigned int size() const {return dataSize;}
bool empty() const {return dataSize == 0;}
// Operator[] should NOT check the value of i
// Add a method called at() that does check i
const T& operator[] (unsigned i) const {return data[i];}
T& operator[] (unsigned i) {return data[i];}
void insert(unsigned int pos, const T& value)
{
if (pos >= dataSize) { throw int(1);}
if (dataSize == reserved)
{
reserve(reserved * 2);
}
// Move the last item (which needs to be constructed correctly)
if (dataSize != 0)
{
new (&data[dataSize]) T(data[dataSize-1]);
}
for(unsigned int loop = dataSize - 1; loop > pos; --loop)
{
data[loop] = data[loop-1];
}
++dataSize;
// All items have been moved up.
// Put value in its place
data[pos] = value;
}
void clear() { erase(0, dataSize);}
void erase(unsigned int erase_index) { erase(erase_index,erase_index+1);}
void erase(unsigned int start, unsigned int end) /* end NOT inclusive so => [start, end) */
{
if (end > dataSize)
{ end = dataSize;
}
if (start > end)
{ start = end;
}
unsigned int dst = start;
unsigned int src = end;
for(;(src < dataSize) && (dst < end);++dst, ++src)
{
// Move Elements down;
data[dst] = data[src];
}
unsigned int count = start - end;
for(;count != 0; --count)
{
// Remove old Elements
--dataSize;
// Remember we need to manually call the destructor
data[dataSize].~T();
}
}
unsigned int begin() const {return 0;}
}; //class vector
With your current memory handling, this vector would only work with plain old data types.
To handle all types, it must ensure that objects
are actually created (malloc doesn't do that),
destroyed (free doesn't do that),
and you can't reallocate memory with realloc, because complex objects are not guaranteed to remain valid if they are byte-wise copied to another location.
Looks like the answer can be found in your question: "When the object reference is returned, a method is invoked and the program segfaults. It seems it can't find this method and ends up in main_arena() in GDB. The type of the object is an inherited class."
You probably store base class instance T in the vector, but make push_back for the instance of the class inherited from T. In push_back {storage[_size] = T(item);} you cast (actually make copy constructor T:T(const T&)) item to T (this probably named 'type cut'), then get reference to T and invoke a method of the class inherited from T using virtual table of T where the method is not defined yet/abstract. Am I right?
To make it properly work you should put T* in the vector or shared_ptr/unique_ptr depending on the ownership terms you apply to vector elements.
Generally in vector you can store only POD (Plain Old Data) types.