When I call r--; My object resets the values to 0. Any ideas?
class MyClass : Superclass {
private:
int length;
int width;
public:
MyClass() {
length = 0;
width = 0;
}
MyClass (int x, int y):Superclass(x/2,y/2){
length = x;
width = y;
}
MyClass operator--(int) {
MyClass temp = *this;
temp.length --;
temp.width --;
return temp;
};
};
Creating and trying the class:
MyClass *r = new MyClass(2,3);
r--; // now length and width = 0 (should be 1,2)
Firstly, the operator doesn't decrement the object it's called on, but the copy it's going to return. It should leave that alone (to return the previous value) and decrement the object:
MyClass temp = *this;
this->length--; // this-> is optional
this->width--;
return temp;
Secondly, r is a pointer. r-- decrements the pointer, not the object it points to, leaving it pointing to an invalid memory location. Dereferencing it afterwards gives undefined behaviour.
I've no idea why you're using new here; you almost certainly just want a variable:
MyClass r(2,3);
r--; // should behave as expected.
If you really do want a pointer for some reason, you'll have to dereference it to get the object:
(*r)--;
and don't forget to delete the object once you've finished with it. And not before.
Related
I'm trying to learn a little bit more of C++!
After working around with memory allocation for a while I got to a place where I'm struggling to understand it.
I wrote a code that works well (not really sure of that but at least doesn't show any memory violation) for a type of initialization (of an object of some class) but it crashes for a similar initialization.
I would appreciate if someone could me explain what is happening and how can I solve this problem.
My thought: The problem is in the line bellow because I'm trying to delete an array of allocated objects when in the problematic initialization I only have one object allocated and not an array.
delete[] pointer; //PROBLEMATIC LINE
PS.: I'm not looking for alternative solutions (like using smart-pointers or whatever). Sorry for my English!
The code:
class class1
{
private:
unsigned int s;
double* pointer;
public:
/* Constructors */
class1() { s = 0; pointer = nullptr; }
class1(unsigned int us, double* uarray)
{
pointer = new double[us];
for (unsigned int i = 0; i < us; i++)
pointer[i] = uarray[i];
}
class1(const class1& other)
{
pointer = new double[s];
for (unsigned int i = 0; i < s; i++)
pointer[i] = other.pointer[i];
}
~class1() { if (!s && pointer != nullptr) delete[] pointer; }
public:
/* Operators Overloading */
class1& operator=(const class1& other)
{
s = other.s;
pointer = new double[s];
for (unsigned int i = 0; i < s; i++)
pointer[i] = other.pointer[i];
return *this;
}
};
class class2
{
private:
unsigned int m;
unsigned int n;
class1* pointer;
public:
/* Constructors */
class2(unsigned int un, double* uarray, bool flag = false) : n(un)
{
m = 1;
pointer = new class1(un, uarray);
if (flag) { this->function(); }
}
~class2() { if (!m && !n) delete[] pointer; }
public:
/* Public Methods */
void function()
{
class1* newpointer = new class1[n];
//**... some code (when commented show the same error)**
delete[] pointer; //**PROBLEMATIC LINE**
pointer = newpointer;
}
public:
/*Template Constructor*/
template<unsigned int m, unsigned int n>
class2(unsigned int um, unsigned int un, double(&uarray)[m][n], bool flag = false) : m(um), n(un)
{
pointer = new class1[um];
for (unsigned int i = 0; i < um; i++)
{
class1 object1(un, uarray[i]);
pointer[i] = object1;
}
if (flag) { this->function(); }
}
};
int main()
{
double test3[] = { 1, 2, 3 };
double test4[][3] = { {3, 2, 1}, {6, 5, 4}, {9, 8, 7} };
double test5[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
class2 m4(3, test3, true); //**NOT OK - VIOLATION OF MEMORY**
class2 m5(3, 3, test4, true); //**OK**
}
Your copy constructor for class1 is not setting the s member, but uses its indeterminate value here:
pointer = new double[s];
causing undefined behavior. Set s from other.s before using it.
Your second constructor has the same problem.
Your assignment operator of class1 is leaking memory, because it doesn't delete[] the previous array.
In class2 you use new in the non-array form, e.g. here:
pointer = new class1(un, uarray);
but in the destructor you call delete[] to delete pointer. This is also causing undefined behavior. Pointers returned from the non-array version of new need to be deleted by delete, e.g. delete pointer.
But since you are also using the array version of new for pointer, you cannot use delete pointer either. As using delete instead of delete[] on a pointer returned from a array-new has also undefined behavior.
Be consistent and use always the array-new, e.g.:
pointer = new class1[1]{{un, uarray}};
class2 causes undefined behavior when an object of its type is copied or moved, because you didn't implement a copy constructor and assignment operator although you have defined a destructor. This is a violation of the rule-of-three.
There is probably more that I missed. The code is not readable at all. Please use proper variable names next time. (I hope that the real code does not use this naming scheme...) E.g. having a non-type template parameter m with the same name as a member of that class and then using m in multiple places of that context is not ok. I had to check the lookup rules to make sure that this actually compiles and does something sensible.
I can't seem to overload the << operator correctly. This is the code I have so far and the instructions for my assignment will be down below. If you point out other mistakes I made that would be kind, BUT my questions is how do I correctly overload my << operator in my case?
INTCOLLECTION.h:
#ifndef INTCOLLECTION_H
#define INTCOLLECTION_H
// Allocate memory in chunks of ints of this size.
const int CHUNK_SIZE = 5;
class IntCollection
{
private:
// The number of ints currently stored in the int
int size;
// the total number of elements available for storage
// in the data array
int capacity;
// A pointer to the dynamically allocated data array
int* data;
// a private member function to allocate more memory
// if necessary
void addCapacity();
public:
// Constructor
IntCollection();
// Destructor
~IntCollection();
// Copy constructor:
IntCollection(const IntCollection &c);
void add(int value);
int get(int index);
int getSize();
IntCollection& operator=(const IntCollection &c);
bool operator==(const IntCollection &c);
IntCollection& operator<<(int value);
};
#endif
INTCOLLECTION.cpp:
#include "IntCollection.h"
#include <iostream>
#include <cstdlib>
using namespace std;
IntCollection::IntCollection()
{
// Initialize member data to reflect an empty
// IntCollection
size = capacity = 0;
data = NULL;
}
IntCollection::~IntCollection()
{
delete [] data;
}
IntCollection::IntCollection(const IntCollection &c)
{
size = c.size;
capacity = c.capacity;
data = c.data;
for(int i = 0; i < c.size; i++)
{
data[i] = c.data[i];
}
}
void IntCollection::addCapacity()
{
// Create a new, bigger buffer, copy the current data to
// it, delete the old buffer, and point our data
// pointer to the new buffer
int *newData;
data = new int[capacity];
capacity += CHUNK_SIZE;
newData = new int[capacity];
for(int i = 0; i < size; i++)
{
newData[i] = data[i];
delete [] data;
data = newData;
}
}
void IntCollection::add(int value)
{
//first, allocate more memory if we need to
if(size == capacity)
{
addCapacity();
}
//Now, add the data to our array and increment size
data[size++] = value;
}
int IntCollection::get(int index)
{
if (index < 0 || index >= size)
{
cout << "ERROR: get() trying to access index out of range.\n";
exit(1);
}
return data[index];
}
int IntCollection::getSize()
{
return size;
}
IntCollection& IntCollection::operator=(const IntCollection &c)
{
size = c.size;
capacity = c.capacity;
data = c.data;
return *this;
}
bool IntCollection::operator==(const IntCollection &c)
{
if((size == c.size) && (capacity == c.capacity))
{
for(int m = 0; m < size; m++)
{
if(data[m] == c.data[m])
{
continue;
}
else
{
return false;
}
}
}
return true;
}
IntCollection& IntCollection::operator<<(int value)
{
return value; // <-- THIS IS WHERE I GET LOST!
/* I also tried changing the parameters to
(IntCollection &b, int value) to return b
but my teacher wants only one parameter
and it wasn't working that way either. */
}
INSTRUCTIONS:
For this assignment you will add a copy constructor, a destructor, and three overloaded operators to the IntCollection class. In the design diagram below, the black member functions represent code that has already been implemented. You will be implementing the green items. Each item that you will be adding to the class is described below the diagram.
Private:
int size // the number of ints currently stored in the int collection
int capacity // total number of elements available in data array
int* data // a pointer to the dynamically allocated data array
void addCapacity(); // private function to allocate more memory if necessary
Public:
IntCollection()
~IntCollection()
IntCollection(const IntCollection &c)
void add(int value)
int get(int index)
int getSize()
IntCollection& operator=(const IntCollection &c)
bool operator==(const IntCollection &c)
IntCollection& operator<<(int value)
The Copy Constructor. The copy constructor should perform a deep copy of the argument object, i.e. it should construct an IntCollection with the same size and capacity as the argument, with its own complete copy of the argument's data array.
The Assignment Operator (=). The assignment operator should also perform a deep copy of the argument object. It must return itself (or more efficiently, a reference to itself) in order to support multiple assignments on the same line, e.g. a = b = c. If you implement your assignment operator first it could be used in the copy constructor, but this is not a requirement.
The Is Equals operator (==). The "is equals" operator should return true if the argument object has the same size as the receiving object, and the values in both objects’ data arrays are identical.
The insertion operator (<<). The insertion operator should add the int parameter into the receiving IntCollection. The functionality is exactly the same as the add() function, i.e. add ints to the collection. Note, however, that this function must return a reference to itself in order to support multiple insertions on the same line, e.g. c << 45 << -210. Unlike the assignment operator, this return must be done by reference, because each insertion actually modifies the IntCollection object, and insertion is done from left to right.
The destructor. Function add() calls addCapacity() to allocate memory when it needs more room. Nowhere in this program is the memory deallocated with delete [], which means we have a memory leak! Add a destructor which correctly handles this.
addCapacity. Note that addCapacity() is a private member function. What happens if you try to call it from outside the class, i.e. by adding the line below to main()?
You need to return *this, i.e. the object being operated upon. Returning "by reference" has the same syntax as returning "by value"; the only difference is in the addition of & to the function declaration, which is already provided.
Try this:
IntCollection& IntCollection::operator<<(int value)
{
add(value);
return *this;
}
The following code constitutes a MCVE, this reproduces the problem I want to ask about but it's not the real code. The real code is quite more complicated so that's why I wrote this for a demonstration of the problem.
The key feature I am looking for is to be able to grow a dynamically allocated array, please do not suggest using the stl because it's explicitly forbidden. This code is for educational purpose and thus there are restrictions.
#include <cstring>
#include <iostream>
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value &operator =(const Value &other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(int value) :
m_absurdPointer(new int[1])
{
*m_absurdPointer = value;
}
Value::Value(const Value &value)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, value.m_absurdPointer, sizeof(*m_absurdPointer));
}
Value &Value::operator =(const Value &other)
{
m_absurdPointer = new int[1];
memcpy(m_absurdPointer, other.m_absurdPointer, sizeof(*m_absurdPointer));
return *this;
}
Value::~Value()
{
delete[] m_absurdPointer;
}
class ValueArray
{
public:
ValueArray();
~ValueArray();
void append(const Value &value);
void show() const;
private:
Value *m_array;
unsigned int m_capacity;
unsigned int m_length;
};
ValueArray::ValueArray() :
m_array(nullptr)
, m_capacity(0)
, m_length(0)
{
}
ValueArray::~ValueArray()
{
delete[] m_array;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr))
memcpy(newarray, m_array, m_capacity * sizeof(*m_array));
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
m_array[m_length++] = value;
}
void
ValueArray::show() const
{
for (size_t i = 0 ; i < m_length ; ++i)
std::cout << static_cast<int>(m_array[i]) << std::endl;
}
int
main(void)
{
ValueArray example;
for (int i = 0 ; i < 10 ; ++i)
example.append(Value(i));
example.show();
return 0;
}
It causes as you can see a double free issue, because the delete[] m_array; calls the destructor of the class Value after it has copied the values to the re-newed array.
I tried to do this with malloc()/realloc() but I need the destructor of Value() to be called so new is mandatory because I can't use free().
How to prevent this?, if I remove the delete[] m_absurdPointer; the double free would be gone of course but there would be a memory leak.
You basically want to implement an own vector class, right?
OK, first things first: As far as I know you cannot grow previously allocated memory. At least not with the standard allocator.
So you need to allocate a new, larger chunk of memory.
You can do this the standard way, using new:
Type * newdata = new Type[size];
In this case the constructor of the class Type will be called for each new element, which is size times.
To get your old data into that new array you need to copy or move it there:
for (size_t it = 0; it < oldsize; ++it) {
newdata[it] = olddata[it];
// newdata[it] = std::move(olddata[it]);
}
This is what std::copy resp. std::move are doing. (You could also use std::swap inside a loop.)
For that to work the Type class needs both a default constructor and a valid implementation of copy or move assignment.
You're using memcpy. In C++, this is generally a bad idea: Your implemented assignment operator isn't called, Therefore both the objects in your old array and the raw copies are using the same pointer, which is why you get that double free, obviously.
You could also allocate raw memory and use placement new to copy or move construct the new objects from the old ones:
void * memory = new char[size * sizeof(Type)];
for (size_t it = 0; it < oldsize; ++it) {
new (memory + it * sizeof(Type)) Type(olddata[it]); // copy
}
The above is only an example, for real code you need to consider alignment, too.
Finally, I'm sure you can somehow trick the default allocator to free your (old) memory without destructing the objects within, this allowing you to use the raw copy memcpy made. Though this would be a hack and could break on complex classes, it's not the C++ way of doing this.
The idiomatic way is to copy or move the old objects to the new storage (with either assignment or construction).
You should use the move-constructor if you have to stick with an vector-like implementation of ValueArray:
class Value
{
public:
Value(int value = 0);
Value(const Value &value);
Value(Value&& val);
Value &operator =(const Value &other);
Value &operator =(Value&& other);
~Value();
operator int() {return *m_absurdPointer;}
private:
int *m_absurdPointer;
};
Value::Value(Value&& o) : m_absurdPointer(o.m_absurdPointer) {
o.m_absurdPointer = nullptr;
}
Value &operator =(Value&& o) {
delete[] this->m_absurdPointer;
this->m_absurdPointer = o.m_absurdPointer;
o.m_absurdPointer = nullptr;
}
void
ValueArray::append(const Value &value)
{
if (m_length >= m_capacity)
{
Value *newarray;
unsigned int unitSize;
unitSize = 1;
newarray = new Value[m_capacity + unitSize];
if ((m_capacity > 0) && (m_array != nullptr)) {
std::move(m_array, m_array + m_length, newarray);
}
delete[] m_array;
m_array = newarray;
m_capacity += unitSize;
}
}
I am writing a operator function for - where my class object is a dynamic array of integer.
the operator takes lhs and rhs object and return an object which is the set of elements in lhs but not in rhs.
though I have written the function but I am not able to return the set since the destructor is called right after the object is returned.
IntegerSet & IntegerSet::operator - (IntegerSet & rhs) const
{
IntegerSet temp(capacity);//local object created to store the elements same size as lhs
int k=0;
int lhssize = ElementSize();//no. of elements in the set
int rhssize = rhs.ElementSize();
for (int i=0;i<lhssize;i++)
{
for (int j=0;j<rhssize;j++)
{
if (rhs.ptr[j]!=ptr[i])
{
k++;
}
}
if(k==rhssize)
{
temp = temp + ptr[i];
}
k=0;
}
return temp;
}
and here is the constructor if you cannot understand the object
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const int & size)//works correctly
{
capacity = size;
ptr = new int [capacity]();
}
IntegerSet::IntegerSet(const IntegerSet & copy) : capacity(copy.capacity)//works correctly
{
ptr = copy.clonemaker();
}
IntegerSet::~IntegerSet()
{
capacity = 0;
delete [] ptr;
}
int * IntegerSet::clonemaker() const // works correctly
{
if(ptr==NULL)
{
return NULL;
}
int *tempptr = new int [capacity];
for(int i=0;i<capacity;i++)
{
tempptr[i]=ptr[i];
}
return tempptr;
}
You'll have to return by value. The local object will be destroyed when the function returns, and there's no way to prevent that.
For that to work, your class will have to correctly follow the Rule of Three to make sure it's correctly copyable. In C++11 or later, you might also consider making it movable, to avoid unnecessary memory allocation and copying (although, in this case, the copy should be elided anyway).
Better still, follow the Rule of Zero and store a vector<int>, which will do all this for you, rather than trying to juggle raw pointers.
You need to change to return the result by value.
IntegerSet IntegerSet::operator - (IntegerSet & rhs) const
Also it would make more sense to supply rhs by const reference when taking a second look.
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.