Operator overloading, destructor memory leak - c++

I've got a problem with destructor in my class.
The main idea is to use operator overloadings in undefined length vectors ex. u can create object which simulates a euclidian vector like RealVector(3) and then use function fillvec() to fill the table with positions x,y,z.
The problem is when I try to use a destructor to delete alocated memory for table.
Here is my code:
class RealVector{
private:
int dim;
double* tab;
public:
RealVector(int dim){
tab=new double[dim];
}
RealVector(const RealVector & other){
dim=other.dim;
tab=new double[other.dim];
for(int i=0; i<dim; i++){
tab[i]=other.tab[i];
}
}
void fillvec(){
for(int i=0; i<dim; i++){
cin >> tab[i];
}
}
void wri(){
cout << "Vector [";
for(int i=0; i<dim; i++){
cout << tab[i];
if(i!=dim-1)
cout<<", ";
}
cout << "]";
}
RealVector operator+(RealVector & o){
for(int i=0; i<dim; i++)
tab[i]+=o.tab[i];
return *this;
}
~RealVector(){
delete [] tab;
}
}
int main(){
RealVector* w1=new RealVector(3);
RealVector* w2=new RealVector(3);
RealVector* answerr=new RealVector(3);
w1->fillvec();
w2->fillvec();
*answerr=*w1+*w2;
answerr->wri();
}
Can someone explain where I have made mistake?

I can see here few critical bugs.
The first one is the main (in your case) I think. The constructor RealVector(int dim) doesn't initialize the dim member. This dim is later used in many member functions while it's value is not initialized. You can fix it by:
RealVector(const int _dim) : dim{_dim}
{
tab=new double[dim];
}
The second bug is that the dim in the operator+ belongs to the current object and might be bigger than dim of the o object. You should use std::min(dim, o.dim) instead.
The third one (thanks to Mooing Duck for pointing out) is that you are missing the operator= implementation. The default assignment operator performs just a 'flat' copy. Since you are using dynamic memory allocation it is critical to implement the 'deep' copy in the operator=. You can find the examples here.
EDIT
Since the c++11 has been tagged here, I would strongly recommend using smart pointers as well as move constructor and move assignment.

Related

Why do passing object as value result in malloc: *** error for object 0x100604c50: pointer being freed was not allocated

I am learning C++ and I am running in a problem that I don't know the reason for.
I have created a vector and matrix class that are light wrappers around a C array that manage a T* array on the heap.
The Matrix class has a function:
// in NBDMatrix.hpp class definition
void makeXMeshgridv1(NBDVector<T> v){ // takes a value
for(unsigned int j=0; j<ny; j++){
for(unsigned int i=0; i<nx; i++)
this->at(i,j) = v.at(i);
}
}
void makeXMeshgridv2(NBDVector<T>& v){ // takes a reference
for(unsigned int j=0; j<ny; j++){
for(unsigned int i=0; i<nx; i++)
this->at(i,j) = v.at(i);
}
}
in main()
NBDVector<float> vec1 = NBDVector<float>(0.0f, 12.6f, 4);
NBDVector<float> vec2 = NBDVector<float>(0.0f, 12.6f, 4);
NBDMatrix<float> mat1(4,8);
NBDMatrix<float> mat2(4,8);
mat1.makeXMeshgridv1(vec1); // causes problem at destruction
mat2.makeXMeshgridv2(vec2); // no problem at destruction
If I use makeXMeshgridv1() I get
malloc: *** error for object 0x100604c50: pointer being freed was not allocated at destruction
but when I use makeXMeshgridv2 everything goes well.
I would like to understand what is the problem when using makeXMeshgridv1().
The one passed by value is likely not being properly deleted when it leaves its scope.
As others have mentioned you need to follow the rule of 0/3/5. The rule of 5 is for optimization so, you can focus on the rule of 0 and 3 for now.
https://en.cppreference.com/w/cpp/language/rule_of_three
This is the example at the page linked.
rule_of_three(const char* s = "")
: rule_of_three(s, std::strlen(s) + 1)
{}
~rule_of_three()
{
delete[] cstring; // deallocate
}
rule_of_three(const rule_of_three& other) // copy constructor
: rule_of_three(other.cstring)
{}
rule_of_three& operator=(rule_of_three other) // copy assignment
{
std::swap(cstring, other.cstring);
return *this;
}

dynamic array in c++: valgrind leak

I'm trying to implement a dynamic array in c++. once it becomes full, its size is doubled and is copied to the double-sized array.
it looks fine but Valgrind says I have a leak.
I should say that I'm not allowed to use any of c++ STL structures- that's why I'm using new[] and delete[] operators.
this is my code:
template<class T>
class DynamicArray
{
int size;
int numOfElements;
T* arr;
public:
DynamicArray(int size) :
size(size), numOfElements(0)
{
arr = new T[size];
}
;
int getSize()
{
return size;
}
int getNumberOfElements()
{
return numOfElements;
}
void insert(T element)
{
arr[numOfElements++] = element;
if (numOfElements == size)
{
T* extended_array = new T[size * 2];
for (int i = 0; i < numOfElements; i++)
{
extended_array[i] = arr[i];
}
delete[] arr;
arr = extended_array;
size = size * 2;
}
}
T& operator[](int i)
{
if (!((i >= 0) && (i < size)))
throw arrayOutOfBoundsException();
return arr[i];
}
~DynamicArray()
{
delete[] arr;
}
class arrayOutOfBoundsException: std::exception
{
};
};
My main program is:
using std::cout;
using std::endl;
void printIntArray(DynamicArray<int> arr){
cout << "size: " << arr.getSize() << "; " << "numOfElemnts: " << arr.getNumberOfElements() << endl;
cout << "array: ";
for(int i=0; i<arr.getNumberOfElements(); i++){
cout << " " << arr[i];
}
cout << endl << endl;
}
int main() {
DynamicArray<int> arr(5);
printIntArray(arr);
arr.insert(1);
arr.insert(2);
arr.insert(3);
printIntArray(arr);
arr.insert(4);
printIntArray(arr);
arr.insert(5);
printIntArray(arr);
arr.insert(6);
printIntArray(arr);
arr.insert(7);
arr.insert(8);
arr.insert(9);
printIntArray(arr);
arr.insert(16);
printIntArray(arr);
arr[9] = 901;
arr[0] = 101;
printIntArray(arr);
**valgrind shows me this error- when the destructor is compiled as comment:
==3954== 80 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3954== at 0x4A07192: operator new[](unsigned long) (vg_replace_malloc.c:363)
==3954== by 0x40103E: DynamicArray<int>::insert(int) (DynamicArray.h:41)
==3954== by 0x400DBC: main (main.cpp:44)**
Can anybody tell me what I was doing wrong? am I misusing "delete[]"? or the destructor?
thanks
The behaviour described by the asker is impossible or
when the destructor is compiled as comment:
means the destructor has been commented out and this is causing the leak. This has been confirmed in a comment. Without the destuctor the last allocation will never be put away.
The Asker's real problem is a Rule of Three Violation.
The short version goes something like this:
If a class requires a user defined copy constructor, assignment operator, or destructor it almost always requires all three.
More on that here: What is The Rule of Three?
In this case,
void printIntArray(DynamicArray<int> arr)
accepts arr by value. This means arr is a copy of the value passed in. In the absence of a custom copy constructor the arr inside printIntArray will point to the same allocation as the source. The copy will be destroyed at the end of printIntArray, and the destructor will delete the allocation, leaving the source pointing to invalid memory so...
DynamicArray<int> arr(5); // allocated storage inside arr
printIntArray(arr); // made a copy of arr that points to same storage.
// Storage freed when copy destroyed
arr.insert(1); // invokes undefined behaviour writing into invalid memory
arr.insert(2); // same
arr.insert(3); // same
printIntArray(arr); // copies arr again. This copy is pointing to the same invalid memory
// and will try to free the allocation a second time when the
// copy is destroyed
The program will almost certainly crash here, making it impossible to leak from the users code. But because the program crashed, Crom only knows what behind-the-scenes structures the runtime was using were not correctly put away.
Whatever happened, as of
arr.insert(1);
the program was deep in Undefined Behaviour and whatever happens after that is anybody's guess. Memory leaks are the least of your worries.
Fixing: Satisfy the Rule of Three
Implement a copy constructor and an assignment operator (We'll ignore the Rule of Five for now.)
You could change
void printIntArray(DynamicArray<int> arr)
to pass by reference
void printIntArray(DynamicArray<int> & arr)
and then
DynamicArray(const DynamicArray &) = delete;
DynamicArray& operator=(const DynamicArray &) = delete;
and disable all copying, but this seems a bit draconian.
Instead lets use Copy and Swap because it's simple and easy to understand. Note that it can also be inefficient, so it's not always the right tool. Here it fits what we want.
DynamicArray(const DynamicArray & src) :
size(src.size), numOfElements(src.numOfElements), arr(new T[size])
{
for (int i = 0; i < numOfElements; i++)
{
arr[i] = src.arr[i];
}
}
DynamicArray& operator=(const DynamicArray src)
{
std::swap(size, src.size);
std::swap(numOfElements, src.numOfElements);
std::swap(arr, src.arr);
return *this;
}
And because who wants to copy they don't need to we'll still
void printIntArray(DynamicArray<int> & arr)
as soon as we're done testing that the copy constructor works correctly.

passing an dynamic array as copy to recursive function c++

I am writing code for a backtracking approach to a Traveling Salesman type of problem. So at each point i will recurse for rest of the un-visited points.
I could not use any library/functions other than cout, cin, new and delete (so no vector). So for the problem i want to keep a track of what all points i have visited till now. I am using a dynamic boolean array for this. So i want to pass the dynamic array to a function as value to keep track of this.
This is what i have tried till now.
I tried to wrap the array in a struct, but the memory dealocation (delete) is giving error (Segmentation fault)
typedef struct Barray{
bool* a;
int size;
Barray(int size) { a = new bool[size]; this->size = size; }
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
~Barray() { delete[] a; } // error
}barray;
This is my recursive function call
void find_mindist(barray visited, int dist_now, int cur_p) {
if (base condition)
{return ;}
for (int i = 0; i < n; i++) {
if (visited.a[i]) continue;
barray tdist = visited;
tdist.a[i] = true;
int ndist = dist_now + dist(points[cur_p], points[i]);
find_mindist(tdist, ndist, i);
}
return ;
}
So my questions are -
how can i pass a dynamic array to a function as value?
Why is the delete above giving error?
First of all, the recommended approach for a local visited information is not the endless copying of the whole visited collection, but a mark->recurse->unmark approach. So whatever you do, please keep a single boolean array for the visited information and update its content to your needs.
The other problems occur because you try to delete an uninitialized pointer in the copy constructor. Also, the assignment operator should be overloaded as well to avoid unpleasent surprises. But non of this really matters if you don't copy your visited information anymore.
The problem this is a copy constructor. As such, on entry, a is uninitialized (so contains garbage), so the delete is invalid.
Barray(const Barray& in) {
if(a) delete[] a; // error
a = new bool[in.size];
this->size = in.size;
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Just remove the delete line. Also, prefer to initialize members, rather
than assign them, so:
Barray(const Barray& in)
: a(new bool[in.size])
, size(in.size) {
for (int i = 0; i < in.size; i++)
a[i] = in.a[i];
}
Also, remember the Rule of Three. You need an copy assignment operator. The simplest is:
Barry& operator=(const Barray& in) = delete;
which just forces a compilation error if you try to use it! Better is:
Barry& operator=(const Barray in) { // **NOTE** pass by value!
std::swap(this.a, in.a);
std::swap(this.size, in.size);
}
This version provides the strong exception guarantee. You aren't allowed to use std::swap, so you'll either have to write your own, or write it out by hand (you choose).
Finally, if you ever find yourself returning a Barray, you should write a move constructor:
Barray(Barray &&in)
: a(in.a)
, size(in.size) {
in.a = nullptr;
}
This can save a lot of copying!

Increasing the size of the custom objects array in c++

I have a class Student and the dynamically created array of students:
class Student{
public:
void create(){
system("cls");
cout << "First name: ";
cin >> fn;
cout << "Last name: ";
cin >> ln;
cout << "How many subjects? ";
cin >> sub_number;
subjects = new string[sub_number];
for(int i = 0; i < sub_number; i++){
cout << "Subject name: ";
cin >> subject[i];
}
}
//This just display the student with a bunch of couts
friend ostream& operator<<(ostream&, const Student&);
~Student(){ delete[] subjects; }
private:
string fn;
string ln;
string* subjects;
int sub_number;
};
I need to increase the size of this array by 1 and add a new student to it.
When I tried to do it by simply:
void main(){
int stu_number = 0;
cout << "How many students? "
cin >> stu_number;
Student* students = new Student[stu_number];
//creating/updating initial students using user input
for(int i = 0; i < stu_number; i++){
students[i].create();
}
//displaying all students
for(int i = 0; i < stu_number; i++){
cout << students[i];
}
//trying to add a student
add_new_student(students, stu_number);
//displaying all students again
for(int i = 0; i < stu_number; i++){
cout << students[i];
}
}
And the add_new_student function:
void add_new_student(Student* students, int& stu_number){
Student* temp = new Student[stu_number++];
for (int i = 0; i < stu_number - 1; i++){
temp[i] = students[i];
}
temp[stu_number - 1].create();
delete[] students;
students = temp;
}
I am getting memory violation errors and Unhandled exceptions: Access violation writing location 0xABABABAB inside the add_new_student function.
What will be the correct way of doing this?
Is Student class missing some important components?
I can't use std::vector or a std::list as this is a school assignment:)
To increase the size of the array, you basically have to:
Create a new array with a larger size
Copy over the values from the old smaller array to the new larger one
Delete the old smaller array
That being said, if you are able to I would recommend switching to std::vector since it has utility methods that will resize for you.
The problem is that your Student class does not follow the "rule of 3":
What is The Rule of Three?
If your class has a user-defined destructor, then it should also provide a user-defined copy constructor and assignment operator. What is happening now is that when this line is performed:
temp[i] = student[i];
you are invoking the assignment operator. However, your Student object, when assigned, will just copy the pointer value from one object to the other. What happens when the destructor for either of these Student objects is called? The destructor will delete the same pointer value twice, thus an error.
Here is a slimmed down version of your current Student class.
#include <string>
class Student
{
std::string* subjects;
std::string fn;
std::string ln;
int sub_number;
public:
Student(size_t numSubjects=5) : subjects(new std::string[numSubjects]),
sub_number(numSubjects){}
~Student() { delete [] subjects; }
};
// Test code
int main()
{
Student s1(10);
Student s2 = s1;
Student s3;
s3 = s1;
}
If you run this program, you will see that there are problems with memory leaks and double deletion errors, as shown here: http://ideone.com/MQhpcK
All I'm doing is copying Student objects, and the issue appears.
To fix the problem, you must add and implement these functions in your Student class:
Student(const Student& rhs); // copy constructor
Student& operator=(const Student& rhs); // assignment operator
Once you implement these functions, test the program above to ensure it truly does make the copies correctly, without memory leaks and segmentation faults/access violation errors. When done, your original issue of the copying causing the access violation should be resolved.
Your problem is caused by the missing assignment operator. In the assignment within the for loop, there is a flat copy of the subjects array which is deleted when the original students array is deleted. After that, there is a so-called dangling pointer in first Student object.
The assignment operator has the job to safely (and semantically correct) copy all elements from one object to another.
Additionally: It would be really interesting (informative) to add some trace output as to get a detailed understanding what's going on here.
Whatever create is called for[1], there must be something wrong with the default constructor[2] of your Student class: it seems to miss initializing important elements that are used within create.
[1] BTW: what is the purpose of create?
[2] Is there a default constructor? What C++ standard is used?

C++ destructor of a class containing a vector of pointers

I have a class that looks like this :
#include <iostream>
#include <vector>
using namespace std;
class MyClass
{
vector<int*> V;
public:
MyClass();
MyClass(int n);
~MyClass();
};
MyClass::MyClass()
{
return;
}
MyClass::MyClass(int n)
{
int* T = new int[n];
for(int i=0; i<n; i++)
{
T[i]=i;
V.push_back(&(T[i]));
}
return;
}
MyClass::~MyClass()
{
for(int i =0; i<V.size(); i++)
delete V[i];
return;
}
int main()
{
MyClass C(5);
return 0;
}
What's wrong about my destructor? I get a "* glibc detected * ./a.out: free(): invalid pointer:..." error upon execution of this.
Do you think I should use ptr_vector? I don't know if I have the courage to learn about those.
Thanks in advance!
EDIT: Your intention is to have a vector of pointers, not arrays, so the problem is with your constructor:
int* T = new int[n];
for(int i=0; i<n; i++)
{
T[i]=i;
V.push_back(&(T[i]));
}
This doesn't create n pointers, but a pointer to n ints.
You should do:
for(int i=0; i<n; i++)
{
V.push_back(new int(i));
}
Before edit:
The problem isn't only in the destructor, but the constructor.
I'm assuming you want to push the array in the vector, in which case you need:
MyClass::MyClass(int n)
{
int* T = new int[n];
for(int i=0; i<n; i++)
{
T[i]=i;
}
V.push_back(T);
return;
}
You're also getting undefined behavior by calling
delete V[i];
instead of
delete[] V[i];
In your destructor, you're deleting pointers that were never allocated. You can only use delete (or delete[]) if there's a specific matching use of new (or new[]), and for n-1 of your int pointers, there is no such call.
If you want your vector to hold pointers to individual unrelated ints, then you need to use new to allocate each one individually. If they're always going to be in an array like this, then keep a pointer to that array in a member, and delete just that one pointer in your destructor.
You are allocating a contiguous block of memory with
int *T = new int[n];
You cannot delete single elements of this block. You can only delete the entire block at once.