Ok, first of all I've written the method, searched stackoverflow beforehand, and noticed my
idea matched the way most people did it, but, the stack doesn't actually get reversed, but instead weird values are put in it:
I'm doing it like this: I make an auxiliary stack and a while loop with the condition size != 0, and then I call aux.push(pop()) since the pop method also returns the deleted element, so the stack should be reversed, and in O(n) time complexity. But, this happens:
STACK TO BE REVERSED: A C D F -> RESULT: Đ Đ `
I ran a memory leak tester, it told me I had 4 times tried to free up already freed space, so I'm thinking that might be the cause.
More details:
Stack implemented as dynamic array
Here is the code with the relevant functions:
template<typename T>
bool NizStek<T>::push(const T& element){
if(_size == _capacity) increaseCapacity();
if(_size == 0){
_brojE++;
_top++;
_array[_top] = new T(element);
}
else{
_size++;
++_top;
_array[_top] = new T(element);
}
}
POP FUNCTION:
template<typename T>
T NizStek<T>::pop(){
if(_size == 0) throw "Stack is empty";
T oldTop = *_array[_top];
delete _array[_top];
_top--;
_size--;
return oldTop;
}
Reverse function:
template<typename T>
void NizStek<T>::reverse() {
NizStek<T> aux;
while(size() != 0){
aux.push(pop());
}
*this = aux;
}
COPY CONSTRUCTOR(OPERATOR = is the same with the first line being delete[] _array;)
template<typename T>
NizStek<T>::NizStek(const NizStek& rhs){
_size = rhs._size;
_capacity = rhs._capacity;
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++) _array[i] = rhs._array[i];
_top = rhs._top;
}
Thanks in advance!
Since you haven't shown it, I'm guessing you are letting the compiler create your copy constructor, which will do a shallow copy. So this:
template<typename T>
void NizStek<T>::reverse()
{
NizStek<T> aux;
while(size() != 0)
{
aux.push(pop());
}
*this = aux; // Potential problem here!
}
Will set this equal to aux's pointer values. Presumably, your destructor frees up the memory, so when aux goes out of scope, the items pointed to in this (this->_array) are no longer allocated ... so you get junk when you attempt to dereference them.
You can fix that by writing your own copy-constructor and actually doing a deep copy of the data (or use move semantics).
EDIT
With your updated copy constructor, you appear to have another issue:
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++)
_array[i] = rhs._array[i]; // this is still a shallow copy!
_top = rhs._top;
The allocation will create an array of pointers, not an array of objects. So you'll have an array of unassigned pointers (this and aux will be pointing to the same items, so when aux clears them out in its destructor, you are still pointing to junk). I think what you wanted was
_niz = new T[_capacity]; // note the lack of *
for(int i=0; i<_size ;i++)
_array[i] = rhs._array[i];
_top = rhs._top;
Or
_niz = new T*[_capacity];
for(int i=0; i<_size ;i++)
{
_array[i] = new T(*rhs._array[i]); // actually do a deep copy
}
_top = rhs._top;
As a side note, if you are concerned about efficiency, you'll probably want to either use a fixed size array, or use a linked-list. Reallocating and copying the memory buffer every time you push an item that requires a new capacity will be very inefficient for a stack structure.
Related
template <class T>
void DArray<T>::add(T value){
if (currentNum==size){
size=size*2;
delete [] dArray;
}
dArray[0]=value;
currentNum++;
}
I just started to learn c++ and learning all these pointer and dynamic array stuff. Really suffering at how to add the value at the beginning of the array and make the value index to the next one such as position+1. Can anyone point out why my value did pass to only dArray [0] when I use cin but did not index to next position.
int val;
for(int i=1; i<=5; i++){
cout << "Please enter integer value number "<<i<< ": ";
cin >> val;
dInt.add(val);
dInt.printAll();
}
Creating your own container class is actually quite a hairy task. Typically most containers are implemented using global new/delete to allocate raw bytes, and then elements are added by calling placement new.
This code is untested, but should be along the right lines (ish). The code could be improved using std::move, but I'll leave that for now...
template <class T>
void DArray<T>::push_back(const T& value) {
if (currentNum == size) {
// just in case size is zero, or something like that
size = std::max(size + 2, size * 2);
// allocate memory (but don't construct objects, yet)
T* temp = ::operator new (sizeof(T) * size);
// copy construct each element
for(auto i = 0; i < currentNum; ++i)
{
// we have to use placement-new here :/
new (temp + i) T(dArray[i]);
// destroy old item
dArray[i].~T();
}
// free the old memory
::operator delete (dArray);
// update to the new array
dArray = temp;
}
// copy construct the new element
new (dArray + currentNum) T(value);
// increment the count
currentNum++;
}
Adding to the start of the array involves moving each element up in the array. As a result, it's a little bit more involved.
template <class T>
void DArray<T>::push_front(const T& value) {
if (currentNum == size) {
// just in case size is zero, or something like that
size = std::max(size + 2, size * 2);
// allocate memory (but don't construct objects, yet)
T* temp = ::operator new (sizeof(T) * size);
// copy construct each element
// this time iterate in reverse
for(auto i = 0; i < currentNum; ++i)
{
// copy old array into new array (starting at index 1)
new (temp + i + 1) T(dArray[i]);
// destroy old item
dArray[i].~T();
}
// free the old memory
::operator delete (dArray);
// update to the new array
dArray = temp;
}
else
{
// copy old elements in array (traverse in reverse order)
for(auto i = currentNum; i > 0; --i)
{
// construct new item (copying previous element)
new (dArray + i) T(dArray[i - 1]);
// call dtor on old element
dArray[i - 1].~T();
}
}
// construct first element in array
new (dArray) T(value);
// increment the count
currentNum++;
}
... and for completeness, the destructor.
template <class T>
DArray<T>::~DArray()
{
for(auto i = 0; i < currentNum; ++i)
{
// call destructor on each element
dArray[i].~T();
}
// free the memory
::operator delete (dArray);
}
This is a reason most people just end up saying "use std::vector"...
I am trying to copy a dynamically allocated array to an instance. My code seems to be copying the values over, but it also need to resize the array to match the "&other" size array.
A little info about the code: There are two classes at hand, one is "Movie" which takes a title, film-time, and director (all pointers) as private members. There is another called "MovieCollection" which is an array that stores each instance of "Movie" in a given index.
//These are private member variables:`
int ArrySize = 50; //There is another section of code that points to this and resizes if needed, I believe it needed a size at runtime though.
//Array to store instance of "movie"
Movie *movieArry = new Movie[ArrySize];
//This is assignment operator
const MovieCollection& operator=(const MovieCollection& other)
{
delete []movieArray;
int otherSizeArry = other.ArrySize;
Movie* temp;
temp = new Movie[otherSizeArry];
for (int i = 0; i < otherSizeArry; i++)
temp[i] = other.movieArry[i];
return *this;
delete []temp;
}
I used another function I wrote to resize the array while the instance is being created. For example, the instance I want to copy over has 10 indexes but the new instance I am trying to copy the values into still has a limit of 50. From what I understand I have to delete it because arrays cannot be resized, then copy the new size over (along with the values).
Any help would be greatly appreciated and thank you in advanced. Also, sorry if more code is required. I didn't want to give more than what was needed.
Your assignment operator is implemented incorrectly. It is freeing the movieArray array before allocating the new temp array. If the allocation fails, the class will be left in a bad state. And you are not assigning the temp array to movieArray before calling return *this; (the delete []temp is never reached, the compiler should have warned you about that).
The operator should look more like this instead:
MovieCollection& operator=(const MovieCollection& other)
{
if (&other != this)
{
int otherSizeArry = other.ArrySize;
Movie* temp = new Movie[otherSizeArry];
for (int i = 0; i < otherSizeArry; ++i) {
temp[i] = other.movieArry[i];
}
// alternatively:
// std::copy(other.movieArry, other.movieArry + otherSizeArry, temp);
std::swap(movieArray, temp);
ArrySize = otherSizeArry;
delete[] temp;
}
return *this;
}
If your class has a copy constructor (and it should - if it does not, you need to add one), the implementation of the assignment operator can be greatly simplified:
/*
MovieCollection(const MovieCollection& other)
{
ArrySize = other.ArrySize;
movieArray = new Movie[ArrySize];
for (int i = 0; i < ArrySize; ++i) {
movieArray[i] = other.movieArry[i];
}
// alternatively:
// std::copy(other.movieArry, other.movieArry + ArrySize, movieArray);
}
*/
MovieCollection& operator=(const MovieCollection& other)
{
if (&other != this)
{
MovieCollection temp(other);
std::swap(movieArray, temp.movieArray);
std::swap(ArrySize, temp.ArrySize);
}
return *this;
}
I am currently tackling this assignment for my computer science class:
Make your own dynamic array template. It should allow creating contiguous arrays (filled with things of the same type) which you can extend without worrying about running out of space.
Do one version using malloc and free.
Do one version using new and delete.
My version using new and delete works flawlessly; however, in trying to convert my new/delete code to using malloc/free, I keep getting a seg fault. I have narrowed down the segfault (I think), to being in a single function: addData. Take a look at the code in my main I used to test this:
Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3->addData(7);
testArray4->printArray();
return 0;
This gives a seg fault; however, when I change it to this:
Array2<int> *testArray3 = new Array2<int>(5);
Array2<int> *testArray4;
testArray3->initArray();
testArray3->printArray();
testArray4 = testArray3; //->addData(7);
testArray4->printArray();
return 0;
There is no seg fault. This makes me believe the issue is in my addData function. Here is the code for that:
Array2<T> *addData(T dataToAdd){
Array2 <T> *tmp;
tmp->data = this->getData();
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
free(tmp->data);
free(this->data);
return newData;
};
I am new to programming as a whole and have not completely wrapped my head around pointers and memory allocation, etc. Any advice you could give me would be greatly appreciated! In case you need to see the rest of the code, here is the entire file I coded my template in. Thank you so much for your time!
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
using namespace std;
template<typename T>
class Array2{
public:
Array2(int size){
this->size = size;
data = (T *) malloc(sizeof(T)*size);
};
Array2<T> *addData(T dataToAdd){
Array2 <T> *tmp;
tmp->data = this->getData();
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
free(tmp->data);
free(this->data);
return newData;
};
~Array2(){
free(this->data);
};
void initArray(){
for (int i = 0; i < this->size; ++i){
//this->data[i] = i;
this->setData(i, i);
}
};
void printArray(){
//ostringstream oss;
string answer = "";
for (int i = 0; i < this->size; ++i){
//oss << this->data[i] + " ";
cout << this->data[i] << " ";
}
//answer = oss.str();
cout << answer << endl;
};
T* getData(){
return this->data;
}
int getSize(){
return this->size;
}
void setData(T data, int index){
this->getData()[index] = data;
}
private:
int size;
T* data;
};
Array2 <T> *tmp;
Allocates a pointer. This does not point the pointer at anything or allocate any storage for the pointer to point at. What it points at without being explicitly assigned is undefined. If you are lucky, and you are this time, tmp points at an invalid location and the program crashes. If you are unlucky, tmp points at some usable region of program memory and lets you write over it, destroying whatever information was there.
tmp->data = this->getData();
Attempts to access the data member at tmp, but fortunately for you the access is in invalid memory and the program comes to a halt. It also has tmp's data pointing at this's data, and that's a dangerous position to be in. Changes to one will happen to the other because they both use the same storage. Also think about what will happen to this->data if you free tmp->data.
Or perhaps I'm wrong and the halt is here for the same reason:
Array2 <T> *newData;
newData->data = (T *) malloc(sizeof(T)*(this->size + 1));
Both need to be fixed. tmp doesn't have to live long, so we can make it a temporary local variable.
Array2 <T> tmp;
Typically this will be created on the stack and destroyed when the function ends and tmp goes out of scope.
But this will not work because Array2's constructor requires a size so it can allocate the array's storage. You need to find out how big to make it. Probably something along the lines of:
Array2 <T> tmp(this->size + 1);
But frankly I don't think you need tmp at all. You should be able to copy the dataToAdd directly into newData without using tmp as an intermediary.
newData is eventually going to be returned to the caller, so it needs a longer scope. Time to use new.
Array2 <T> *newData = new Array2 <T>(this->size + 1);
And through the magic of the constructor... Wait a sec. Can't use new. That makes this hard. malloc doesn't call constructors, so while malloc will allocate resources for newData, it doesn't do the grunt work to set newData up properly. Rule of thumb is Never malloc An Object. There will be exceptions I'm sure, but you shouldn't be asked for this. I recommend using new here and politely telling the instructor they are on crack if they complain.
Anyway, new Array2 <T>(this->size + 1) will allocate the data storage for you with it's constructor.
There is an easier way to do this next bit
for (int i = 0; i < tmp->getSize() + 1; ++i){
if (i < tmp->getSize()){
//newData->data[i] = tmp->data[i];
newData->setData(tmp->getData()[i], i);
}
else{
//newData->data[i] = dataToAdd;
newData->setData(dataToAdd, i);
}
}
Try:
for (int i = 0; i < tmp->size; ++i){
newData->data[i] = tmp->data[i]; // you were right here
}
newData->data[tmp->size] = dataToAdd;
And back to something I hinted at earlier:
free(tmp->data);
free(this->data);
Both tmp->data and this->data point to the same memory. To be honest I'm not sure what happens if you free the same memory twice, but I doubt it's good. Regardless, I don't think you want to free it. That would leave this in a broken state.
Recap and fixes
Array2<T> *addData(T dataToAdd)
{
Array2 <T> *newData = new Array2 <T>(this->size + 1);
for (int i = 0; i < this->size; ++i)
{
newData->data[i] = this->data[i];
}
newData->data[this->size] = dataToAdd;
return newData;
};
This version leaves this intact and returns a newData that is one bigger than this. What it doesn't do is add anything to this. Which is goofy for a method named addData.
It also leads to stuff like this:
mydata = myData->addData(data);
which leaks memory. The original mydata is lost without deletion, resulting in a memory leak.
What I think you really need is a lot simpler:
Array2<T> & addData(T dataToAdd)
{
this->data = realloc(this->data, this->size + 1);
this->data[this->size] = dataToAdd;
this->size++;
return *this;
};
realloc effectively allocates a new buffer, copies the old buffer into the new one, and frees the old buffer all in one fell swoop. Groovy.
We then add the new element and increment the count of elements stored.
Finally we return a reference to the object so it can be used in a chain.
Usage can be
myData.addData(data);
myData.addData(data).addData(moredata);
myData.addData(data).printArray();
and if you have operator << support written
std::cout << myData.addData(data) << std::endl;
I'd go back over the new version of Array if I were you. Most of the bugs picked off here are conceptual errors and also apply to it. You might just be getting unlucky and it merely looks like it works. I just read C++ Calling Template Function Error. The posted solutions fixed the immediate problem, but did not touch the underlying memory management problems.
As for the rest of your class, I advice following the link and answering What is The Rule of Three? Because Array2 violates the heck out of it.
Here's my code:
template<class T> class Test
{
public:
int Size = 0;
int Length = 0;
T* Items;
Test() {}
~Test()
{
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length + 250];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
}
Items[Size] = newItem;
Size++;
}
};
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
I'm populating the dynamic array with 500000 integers which must take just 1-2Mb but it takes about 30Mb. There's no problem if i set the initial size to 500000(i.e. no resizing occurring). The grow value(250) seems to affect the memory somehow, if it's larger(for example 1000) then the memory usage is pretty low. What's wrong?
Typically, when you are reallocating an array, you do not want to modify the actual array until the very last second (to maintain exception safety):
T* temp = new T[new_size];
// assume count is the previous size and count < new_size
std::copy(Items, Items + count, temp);
std::swap(temp, Items);
delete [] temp;
Aside from that, there is nothing visible in your code that would cause a memory leak.
The extra size can possibly be due to other optimizations (being turned off) and/or debugging symbols being turned on. What compiler options are you using (and what compiler)? It should be noted that extra size is not necessarily an indication of a memory leak. Have you run this in a debugger or memory profiler which found a leak?
It should also be noted that std::vector does all of this for you.
Looking at your code, you're going to segfault more so than leak memory due to the fact that calling delete or delete[] on a non-NULL, but previously deallocated, pointer is a Bad Thing. Also, I don't believe this is your real code, because what you posted won't compile.
When you delete a pointer, always set it to NULL afterwards. It's good practice to initialize to NULL as well. Let's fix up your code to make sure we don't call delete on previously deallocated pointers. Also, let's initialize our pointer to NULL.
Your misuse of memory probably stems from the following lines of code:
Length += 250;
T* old = Items;
Items = new T[Length + 250];
Notice that you increment Length by 250, but then allocate Length+250 more elements? Let's fix that, too.
template<class T>
class Test
{
public:
int Size;
int Length;
T* Items;
Test() : Size(0), Length(0), Items(NULL){}
~Test() {
if (Items != NULL)
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
old = NULL;
}
Items[Size] = newItem;
Size++;
}
};
int main(){
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
}
I'm working on an email validation program for my cmpsci class and am having trouble with this one part.
What I'm doing is reading a list of valid top level domains from a text file into a vector class I wrote myself (I have to use a custom vector class unfortunately). The problem is that the program reads in and adds the first few domains to the vector all well and fine, but then crashes when it gets to the "org" line. I'm completely stumped why it works for the first few and then crashes.
Also, I have to use a custom string class; that's why I have the weird getline function (so I get the input in a char* for my String constructor). I've tried using the standard string class with this function and it still crashed in the same way so I can rule out the source of the problem being my string class. The whole program is quite large so I am only posting the most relevant parts. Let me know if more code is needed please. Any help would be awesome since I have no clue where to go from here. Thanks!
The ReadTlds function:
void Tld::ReadTlds() {
// Load the TLD's into the vector
validTlds = Vector<String>(0); // Init vector; declaration from header file: "static Vector<String>validTlds;"
ifstream in(TLD_FILE);
while(!in.eof()) {
char tmpInput[MAX_TLD_LENGTH]; // MAX_TLD_LENGTH equals 30
in.getline(tmpInput, MAX_TLD_LENGTH);
validTlds.Add(String(tmpInput)); // Crashes here!
}
}
My custom vector class:
#pragma once
#include <sstream>
#define INIT_CAPACITY 100
#define CAPACITY_BOOST 100
template<typename T> class Vector {
public:
// Default constructor
Vector() {
Data=NULL;
size=0;
capacity=INIT_CAPACITY;
}
// Init constructor
Vector(int Capacity) : size(0), capacity(Capacity) {
Data = new T[capacity];
}
// Destructor
~Vector() {
size=0;
Data = NULL;
delete[] Data;
}
// Accessors
int GetSize() const {return size;}
T* GetData() {return Data;}
void SetSize(const int size) {this->size = size;}
// Functions
void Add(const T& newElement) {
Insert(newElement, size);
}
void Insert(const T& newElement, int index) {
// Check if index is in bounds
if((index<0) || (index>capacity)) {
std::stringstream err;
err << "Vector::Insert(): Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Check capacity
if(size>=capacity)
Grow();
// Move all elements right of index to the right
for(int i=size-1; i>=index; i--)
Data[i+1]=Data[i];
// Put the new element at the specified index
Data[index] = newElement;
size++;
}
void Remove(int index) {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector::Remove():Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Move all elements right of index to the left
for(int i=index+1; i<size; i++)
Data[i-1]=Data[i];
}
// Index operator
T& operator [] (int index) const {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector operator[]:Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
return Data[index];
}
// Assignment oper
Vector<T>& operator = (const Vector<T>& right) {
Data = new T[right.GetSize()];
for(int i=0; i<right.GetSize(); i++)
Data[i] = right[i];
size = right.GetSize();
return *this;
}
private:
T *Data;
int size; // Current vector size
int capacity; // Max size of vector
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
// Dispose old array
Data = NULL;
delete[] Data;
// Assign new array to the old array's variable
Data = newData;
}
};
The input file:
aero
asia
biz
cat
com
coop
edu
gov
info
int
jobs
mil
mobi
museum
name
net
org <-- crashes when this line is read
pro
tel
travel
The error Visual Studio throws is:
Unhandled exception at 0x5fb04013 (msvcp100d.dll) in Email4.exe: 0xC0000005: Access violation reading location 0xabababbb.
The problem is in your grow function:
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
You increase the capacity, but then copy elements that didn't exist in the old array. It should be something like:
void Grow() {
int old_capacity = capacity;
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<old_capacity; i++)
newData[i] = Data[i];
You also NULL out Data before deleting it in both Grow and the destructor, which causes a memory leak. In both cases, you really don't need to set it to NULL at all, since there's no change of it being accidentally double-deleted (in Grow it's set to a new pointer immediately, in the destructor the object's lifetime is over). So just
delete[] Data;
alone is fine.
Also I think
if(size>=capacity)
can be:
if(size == capacity)
since size should never be over capacity. That would mean you'd already overflowed the buffer.
Matthew is probably right. Still, there's a valuable lesson to be learned here.
When you hit a problem like this, don't stop walking your code in your ReadTlds function. Keep walking inside the Vector class. Functions like Insert and Grow probably hold the error, but if you don't walk through them, you'll never find it.
Debugging is it's own very special skill. It takes a long time to get it down pat.
edit it's a late night and I misread your code, but I left my post to comment back
Also in the default ctor you do
Data = NULL;
capacity=INIT_CAPACITY;
(EDIT: expanded explanation here)
But never allocate the memory for Data. Shouldn't it be:
Vector() {
Data= new T[INIT_CAPCITY];
size=0;
capacity=INIT_CAPACITY;
}
And remove is missing
--size
EDIT:
Fellow readers help me out here:
Data is of type T* but everywhere else you are assigning and allocating it just like T instead of T* . My C++ days are too long gone to remember whether using a T& actually resolves this.
Also I can't remember that if you have an array of pointers and destruct it, that the dtor for the single instances in the array are destroyed.
Also in the assignment operator, wouldn't you be copying the pinters? so you just have to rely on the fact the the instance where you copyid from is never deleted (because then your objects would be dead too).
hth Mario