For my code, expand is to double the capacity of the vector. It should dynamically reallocate memory for the dynamically allocated array and update the value of capacity while not creating a memory leak.
I was wondering how you would check for a memory leak as my testing doesn't show execution times in Visual Studio.
void IntVector::expand(){
cap = cap * 2;
int *data2;
data2 = data;
IntVector::~IntVector();
data = new int[cap];
data = data2;
delete data2;
}
header (I understand that you aren't supposed to be using namespace std).
#ifndef INTVECTOR_H
#define INTVECTOR_H
using namespace std;
class IntVector{
private:
unsigned sz;
unsigned cap;
int *data;
public:
IntVector();
IntVector(unsigned size);
IntVector(unsigned size, int value);
unsigned size() const;
unsigned capacity() const;
bool empty() const;
const int & at (unsigned index) const;
const int & front() const;
const int & back() const;
~IntVector();
void expand();
};
#endif
main file
#include "IntVector.h"
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
IntVector::IntVector(){
sz = 0;
cap = 0;
data = NULL;
}
IntVector::IntVector(unsigned size){
sz = size;
cap = size;
data = new int[sz];
*data = 0;
}
IntVector::IntVector(unsigned size, int value){
sz = size;
cap = size;
data = new int[sz];
for(int i = 0; i < sz; i++){
data[i] = value;
}
}
unsigned IntVector::size() const{
return sz;
}
unsigned IntVector::capacity() const{
return cap;
}
bool IntVector::empty() const{
if(sz > 0){
return false;
}
else{
return true;
}
}
const int &IntVector::at(unsigned index) const{
if(index > sz){
exit(1);
}
else{
return data[index];
}
}
const int &IntVector::front() const{
return data[0];
}
const int &IntVector::back() const{
return data[sz];
}
IntVector::~IntVector(){
delete data;
}
void IntVector::expand(){
cap = cap * 2;
int *data2;
data2 = data;
IntVector::~IntVector();
data = new int[cap];
data = data2;
delete data2;
}
Edit::
void IntVector::expand(){
cap = cap * 2;
int *data2 = data;
data = new int[cap];
delete[] data2;
delete data2;
}
These 2 lines:
data = new int[cap];
data = data2;
Allocate an array of ints, and then immediately override the pointer leading to it, thereby losing that allocated memory for ever. That's a memory leak.
Using valgrind or similar tools should lead to these errors very easily.
To test for memory leaks in Visual Studio:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
and this next line will automatically display a memory-leak report at every place in your code where an application exit occurs.
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Edited for maxywb
I use task manager from windows.
in windows 8:
Details tab -> right click on a column and 'select columns' -> GDI objects
Keep an eye on this column, if this keeps rising while it shouldn't then you have a leak.
Related
I'm trying to make an ArrayList, an ADT object that uses dynamically allocated arrays to store data. It's supposed to mimic the vector class in that all I want the object to do is:
store data in a dynamically array
I want to define a default constructor (but I don't want to define any of the big three if I don't need to, and I don't think I need to)
have a working size function that returns the current size of the object's array, i.e the size of the list
an at() function
an insert(index, value) function
a remove(index) function
I keep getting leakage errors tho :(
I have attached my code for my header file, and a cpp file where I define my member functions. Does anyone think they can take a quick look at my code and tell me what I'm doing wrong?
header file:
#ifndef ARRAYLIST_H
#define ARRAYLIST_H
#include <cstdlib>
// declare class here
class ArrayList{
private:
int listSize;
int* arr;
public:
ArrayList();
int size() const;
int at(int index) const;
void insert(int index, int value);
void remove(int index);
};
#endif // ARRAYLIST_H
#include <stdexcept> //
#include "ArrayList.h"
// define class methods here
ArrayList::ArrayList() {
listSize = 0;
arr = new int[listSize];
}
int ArrayList::size() const{
return listSize;
}
int ArrayList::at(int index) const{
return arr[index];
}
void ArrayList::insert(int index, int value) {
// make a tempArr
// make listSize the listSize+1
// iterate through new tempArr and make it the same as arr until index is reached.
// at index, do tempArr[index] = value;
listSize++;
int* tempArr = new int[listSize];
for(int i = 0; i < listSize; i++){
if(i < index){
tempArr[i] = arr[i];
}
else if(i == index){
tempArr[index] = value;
}
else{
tempArr[i] = arr[i - 1];
}
delete [] arr;
arr = tempArr;
}
}
void ArrayList::remove(int index){
listSize--;
int* tempArr = new int[listSize]; // making a temporary dynamically allocated arr
for(int i = 0; i < listSize; i++){
if(i == index){ // skipping copying this element
continue;
}
tempArr[i] = arr[i];
delete [] arr;
arr = tempArr;
}
}
I have a problem with my code, and I don't understand what is wrong with it.
This is the were the problem occurs in the code:
void Safe_Array::resize(unsigned new_capacity)
{
score += sizeof(int)*(new_capacity - m_capacity);
if (m_capacity < new_capacity)
{
int old_len = m_capacity - 1;
Safe_Array temp(*this);
if (m_data)
delete[] m_data;
m_data = new int[sizeof(int)*new_capacity]; // new allocation
m_capacity = new_capacity;
for (int i = 0; i < old_len + 1; i++)
m_data[i] = temp.m_data[i];
for (; old_len < new_capacity; old_len++)
m_data[old_len] = 0;
}
else // here we need to shorten the array
{
Safe_Array temp(*this);
if (m_data)
delete[] m_data;
m_data = new int[sizeof(int)*new_capacity]; // new allocation
m_capacity = new_capacity;
for (int i = 0; i < new_capacity; i++)
m_data[i] = temp.m_data[i];
}
}
I encounter the error when I try to delete m_data.
The purpose of this function:
first I have created an object that m_data is its array, resize is a function that will as it say "resize" this field of the object.
Here is the Header file:
class Safe_Array
{
public:
Safe_Array(unsigned capacity = 0, const int max_tries = 3);
Safe_Array(const Safe_Array&);
~Safe_Array();
void show(void) const;
unsigned get_capacity() const;
bool insert(int, unsigned);
bool get(unsigned index, int &value) const;
bool search(int value, unsigned &index) const;
Safe_Array& assign(const Safe_Array&);
void resize(unsigned);
void sort();
static unsigned get_score();
friend int compare(const Safe_Array& a, const Safe_Array& b);
Safe_Array& create(unsigned index1, unsigned index2);
private:
int *m_data;
unsigned m_capacity;
static unsigned score;
const int m_max_tries;
unsigned int counter;
};
Here is the cpp file of the function. (including distractor, contractor, copy contractor, and the function resize):
Safe_Array::Safe_Array(unsigned capacity, int max_tries) :
m_max_tries(max_tries), m_capacity(0), m_data(NULL), counter(0)
{
m_capacity = capacity;
//counter = 0; // when created counter = 0
m_data = new int[capacity];
memset(m_data, 0, m_capacity*sizeof(int));
score += sizeof(Safe_Array) + sizeof(int)*m_capacity;
}
Safe_Array::Safe_Array(const Safe_Array& org_obj) :
m_max_tries(org_obj.m_max_tries), m_capacity(org_obj.m_capacity), counter(0) // copy constractor
{
m_data = new int[m_capacity];
memcpy(m_data, org_obj.m_data, m_capacity * sizeof(int)); // copy sizeof(int)*4 -> int is 4 bytes & memcpy copies bytes
score += sizeof(Safe_Array) + sizeof(int)*m_capacity;
}
Safe_Array::~Safe_Array() // distractor
{
if (m_data) // check if object exists
delete[] m_data;
score -= sizeof(Safe_Array) + sizeof(int)*m_capacity; // uptade score
}
probably Safe_Array temp(*this); do not copy (deeply) m_data, so after the delete you look at a freed memory.
Moving the delete later :
if (m_data) {
int * old = m_data;
m_data = new int[sizeof(int)*new_capacity]; // new allocation
m_capacity = new_capacity;
for (int i = 0; i < old_len + 1; i++)
m_data[i] = old[i];
delete[] old;
}
To clone the current instance just to (hope to) save a member of it is a bad way.
I have a header and .cpp file. I am having difficulty initializing the array. The problem is that I can't specify the array size. The size depends on the number of elements the user inputs. When I make a new dynamicArray, I believe I have to use the "new" like dynamicArray = new string[sizeof(array)] (because I have to delete the memory later according to the assignment) but when I run it through Linux, it says that it cannot appear in a constant - expression.
I'm still a little unfamiliar with C++. Any feedback is appreciated.
What the error looks like:
I also had issues with the header redefinition and I think the #pragma once helped.
I know #include "stdafx.h" is bad for linux. I remove it every time I run it on linux.
DynamaicStringArray.cpp
// DynamicStringArray.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "DynamicStringArray.h"
#include "Assignment9Test_V1.cpp"
// copy constructor that copies the array
DynamicStringArray::DynamicStringArray(string array[]) {
// string *dynamicArray = new string[sizeof(array)]; // without pointer, error with conversion between types
dynamicArray = new string[sizeof(array)];
for (int i = 0; i < sizeof(array); i++) {
dynamicArray[i] = array[i];
}
}
// default constructor
DynamicStringArray::DynamicStringArray() {
size = 0;
dynamicArray = NULL;
// dynamicArray = new string[size];
}
// frees up dynamic array memory
void DynamicStringArray::destructor(string array[]) {
delete[] array;
array = NULL;
}
// return number of entries in array
int DynamicStringArray::getSize() {
return size;
}
// creates a new dynamic array one element larger than dynamicArray
// copies all elements of dynamicArray to new array and
// add new string to end of new array
// increment size
// delete old dynamicArray
// set new array as dynamicArray
void DynamicStringArray::addEntry(string newString) {
string *newArray;
newArray = new string[size + 1];
for (int i = 0; i < size; i++) {
newArray[i] == dynamicArray[i];
}
int endIndex = sizeof(newArray);
newArray[endIndex] = newString;
destructor(dynamicArray);
dynamicArray = newArray;
}
// searches for dynamicArray for specific string,
// if string not found, return false
// if string is found, create new one size smaller dynamic array
// than dynamicArray
// copy elements of old dynamicArray to new array without the string
// delete old dynamicArray
// decrement size
// return true
bool DynamicStringArray::deleteEntry(string deleteMe) {
string *newArray;
newArray = new string[size - 1];
bool isFound = false;
for (int i = 0; i < size; i++) {
if (dynamicArray[i] == deleteMe) {
i++;
isFound = true;
}
else if (dynamicArray[i] != deleteMe) {
newArray[i] == dynamicArray[i];
}
}
if (isFound) {
return true;
destructor(dynamicArray);
dynamicArray = newArray;
}
else if (!isFound) {
return false;
}
}
// returns the string at that index
string DynamicStringArray::getEntry(int findMe) {
return dynamicArray[findMe];
}
DynamicStringArray.h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class DynamicStringArray {
public:
DynamicStringArray();
DynamicStringArray(string array[]);
// overloading the assignment operator
void destructor(string array[]);
int getSize();
void addEntry(string);
bool deleteEntry(string);
string getEntry(int);
private:
int size; // holds number of entries in the array
string *dynamicArray; // references a dynamic array of type string
};
Your instinct to use new (specifically, new[] and delete[]) to solve this issue is correct. You must dynamically allocate the array at runtime since you don't know the number of elements at compile-time. However, you are not using new[]/delete[] correctly, which is why you are getting errors (amongst many other problems with your code).
Try something more like this instead:
DynamicStringArray.h
#pragma once
#include <string>
class DynamicStringArray {
public:
DynamicStringArray();
DynamicStringArray(const std::string *array, int arraySize);
DynamicStringArray(const DynamicStringArray &array);
~DynamicStringArray();
DynamicStringArray& operator=(const DynamicStringArray &array);
int getSize() const;
void addEntry(const std::string &newString);
bool deleteEntry(const std::string &deleteMe);
std::string getEntry(int findMe) const;
private:
int size; // holds number of entries in the array
string *dynamicArray; // references a dynamic array of type string
};
DynamicStringArray.cpp
// DynamicStringArray.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "DynamicStringArray.h"
// default constructor
DynamicStringArray::DynamicStringArray() {
size = 0;
dynamicArray = NULL;
}
// constructor that copies an array
DynamicStringArray::DynamicStringArray(const std::string *array, int arraySize) {
size = arraySize;
dynamicArray = new std::string[size];
for (int i = 0; i < size; i++) {
dynamicArray[i] = array[i];
}
}
// copy constructor that copies the array
DynamicStringArray::DynamicStringArray(const DynamicStringArray &array) {
size = array.size;
dynamicArray = new std::string[size];
for (int i = 0; i < size; i++) {
dynamicArray[i] = array.dynamicArray[i];
}
}
// frees up dynamic array memory
DynamicStringArray::~DynamicStringArray() {
delete[] array;
}
// copy assignment operator that copies the array
DynamicStringArray& DynamicStringArray::operator=(const DynamicStringArray &array) {
if (&array != this) {
DynamicStringArray copied(array);
std::string *temp = copied.dynamicArray;
copied.dynamicArray = dynamicArray;
dynamicArray = temp;
size = array.size;
}
return *this;
}
// return number of entries in array
int DynamicStringArray::getSize() const {
return size;
}
// creates a new dynamic array one element larger than dynamicArray
// copies all elements of dynamicArray to new array and
// add new string to end of new array
// increment size
// delete old dynamicArray
// set new array as dynamicArray
void DynamicStringArray::addEntry(const std::string &newString) {
std::string *newArray = new std::string[size + 1];
for (int i = 0; i < size; i++) {
newArray[i] = dynamicArray[i];
}
newArray[size] = newString;
delete[] dynamicArray;
dynamicArray = newArray;
++size;
}
// searches the dynamic array for a specific string,
// if string not found, return false
// if string is found, create new array one size smaller than dynamicArray
// copy elements of old dynamicArray to new array without the string
// delete old dynamicArray and replace with new array
// decrement size
// return true
bool DynamicStringArray::deleteEntry(const string &deleteMe) {
for (int i = 0; i < size; i++) {
if (dynamicArray[i] == deleteMe) {
std::string *newArray = new std::string[size - 1];
for (int j = 0; j < i; ++j) {
newArray[j] = dynamicArray[j];
}
for (int j = i+1; j < size; ++j) {
newArray[j-1] = dynamicArray[j];
}
delete[] dynamicArray;
dynamicArray = newArray;
--size;
return true;
}
}
return false;
}
// returns the string at that index
std::string DynamicStringArray::getEntry(int findMe) const {
return dynamicArray[findMe];
}
That being said, using a std::vector is the preferred solution. It is a dynamic-sized array that wraps new[]/delete[] for you. It is simpler and safer to use than using new[]/delete[] directly, eg:
DynamicStringArray.h
#pragma once
#include <string>
#include <vector>
class DynamicStringArray {
public:
DynamicStringArray();
DynamicStringArray(const std::string *array, int arraySize);
int getSize() const;
void addEntry(const std::string &newString);
bool deleteEntry(const std::string &deleteMe);
std::string getEntry(int findMe) const;
private:
std::vector<std::string> dynamicArray; // dynamic array of type string
};
DynamicStringArray.cpp
// DynamicStringArray.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "DynamicStringArray.h"
#include <algorithm>
// default constructor
DynamicStringArray::DynamicStringArray() {
}
// copy constructor that copies the array
DynamicStringArray::DynamicStringArray(const std::string *array, int arraySize) :
dynamicArray(array, array + arraySize) {
}
// return number of entries in array
int DynamicStringArray::getSize() const {
return dynamicArray.size();
}
// appends a new element to the end of the dynamic array
void DynamicStringArray::addEntry(const std::string &newString) {
dynamicArray.push_back(newString);
}
// searches the dynamic array for a specific string,
// if string not found, return false
// if string is found, remove it and return true
bool DynamicStringArray::deleteEntry(const std::string &deleteMe) {
std::vector<std::string>::iterator iter = std::find(dynamicArray.begin(), dynamicArray.end(), deleteMe);
if (iter != dynamicArray.end())
{
dynamicArray.erase(iter);
return true;
}
return false;
}
// returns the string at that index
std::string DynamicStringArray::getEntry(int findMe) const {
return dynamicArray[findMe];
}
So I am trying to create a stack with a dynamic size, meaning that the capacity of the stack will change dynamically as needed. The concept worked out flawlessly in my head, create a function name memoryManagement(int i) that takes the size of data currently stored in the stack by a variable called usedCapacity. After this, the program was supposed to create a new array, use memcpy to copy the contents of the old array onto the new one. And finally, copy the contents of the new array back onto the old one with a new capacity. However, I keep getting a runtime error when I run my program. Also, depending in where I call the showStack function I sometimes get thrash numbers instead of the actual values I pushed onto the stack. If anyone could point me out on what I am doing wrong, I would greatly appreciate it.
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
using namespace std;
class Stack
{
public:
//stack functions
Stack();
void push(int a);
int pop();
int peek() const;
void showStack();
~Stack();
//memory management
void memoryManagement(int a);
//void setCapacity(int );
//void ensureCapacity(int minCapacity);
private:
int top;
int * arr;
int capacity;
int usedCapacity;
};
//////////////////////////////////////////////////////////////////////////////////
int main() {
Stack calc;
calc.push(11);
calc.push(33);
calc.showStack();
calc.push(23);
calc.push(43);
return 0;
}
//////////////////////////////////////////////////////////////////////////////////
Stack::Stack()
{
top = -1;
usedCapacity = 0;
capacity = 1;
arr = new int[capacity];
}
void Stack::push(int a)
{
if (top > capacity)
throw "Stack overflow";
top++;
usedCapacity++;
arr[top] = a;
memoryManagement(usedCapacity);
}
int Stack::pop()
{
if (top <= -1)
throw "Stack underflow";
arr[--top];
}
int Stack::peek() const
{
return top;
}
void Stack::showStack()
{
for (int i = 0; i < capacity; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
Stack::~Stack()
{
delete[] arr;
}
void Stack::memoryManagement(int a)
{
if (a >= capacity)
{
int newCapacity;
newCapacity = (a * 3) / 2 + 1;
int * arr2 = new int[newCapacity];
memcpy(arr2, arr, sizeof(int) * usedCapacity);
delete[] arr;
arr = arr2;
delete[] arr2;
}
}
Why are you deleting arr2 from memoryManagement? You should not, as that's apparently your new class attribute (you did arr = arr2):
But that's not enough (your program will then start throwing exception upon push....because you also forgot to modify your capacity attribute. Here is your working memoryManagement function:
void Stack::memoryManagement(int a)
{
if (a >= capacity)
{
int newCapacity;
newCapacity = (a * 3) / 2 + 1;
int * arr2 = new int[newCapacity];
memcpy(arr2, arr, sizeof(int) * usedCapacity);
delete[] arr;
arr = arr2;
capacity = newCapacity; // Don't forget that!
//delete[] arr2; // Don't do that!
}
}
I have read few topics about same problem, but i can't find what's wrong in my code. This is header file:
#pragma once
class Queue
{
private:
float *elements;
int count;
float newElement;
public:
Queue();
Queue(int);
Queue(Queue &);
~Queue();
void enqueue(float);
float dequeue();
int getCount();
};
And .cpp file:
#include "Queue.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Queue::Queue()
{}
Queue::Queue(int arrSize)
{
this->count = arrSize;
float *elements = new float[arrSize];
for(int i = 0; i < arrSize - 1; i++)
{
newElement = rand()% 4000;
newElement /= 100;
elements[i] = newElement;
}
}
void Queue::enqueue(float element)
{
size_t newSize = count + 1;
float *new_elements = new float[newSize];
memcpy(new_elements, elements, newSize);
count = newSize;
delete [] elements;
elements = new_elements;
elements[count] = element;
}
float Queue::dequeue()
{
float firstElement = elements[0];
size_t newSize = count - 1;
float *new_elements = new float[newSize];
memcpy(new_elements, elements, newSize);
count = newSize;
delete [] elements;
elements = new_elements;
return firstElement;
}
int Queue::getCount()
{
return count;
}
Queue::~Queue()
{
delete [] elements;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
Queue queue(4);
queue.enqueue(3);
}
I was trying to figure out where my mistake is, but I'm begginer in C++.
I think that something is wrong i my "dequeue" method, by after trying to fix it, it's still the same.
There are several problems
The default constructor doesn't initialize its members
Queue::Queue(int arrSize) has a local variable elements, which shadows the member elements. The consequence, this constructor doesn't initialize its member
enqueue should copy count * sizeof(float) bytes, not newSize bytes
as #Vladimir noticed, enqueue assigns one element beyond the allocated memory. Should be elements[count - 1] = element;
dequeue should copy newSize * sizeof(float) bytes, not newSize bytes