I'm trying to create a vector of structs which each have a an array of pointers. However, I can't seem to delete the vector without a memory problem.
When I run valgrind
==29801== Invalid free() / delete / delete[] / realloc()
==29801== at 0x4A05A36: operator delete (vg_replace_malloc.c:515)
==29801== by 0x4009D4: test_struct::~test_struct() (in /home/hltcoe/rcotterell/code-switching/a.out)
==29801== by 0x40142B: void std::_Destroy(test_struct*) (in
/home/hltcoe/rcotterell/code-switching/a.out)
==29801== by 0x401299: void std::_Destroy_aux::__destroy(test_struct*,
test_struct*) (in /home/hltcoe/rcotterell/code-switching/a.out)
EDIT
#include <vector>
using namespace std;
struct test_struct {
public:
int * array;
test_struct() {
array = NULL;
}
~test_struct() {
delete[] array;
}
private:
test_struct(const test_struct& that);
test_struct& operator=(const test_struct& that);
};
int main(int argc, char ** argv) {
vector <test_struct> data;
for (int i = 0; i < 5; ++i) {
test_struct tmp;
tmp.array = new int[5];
data.push_back(tmp);
}
}
And it gives the following compile error. Any ideas?
You should follow rule of three or Use STL container where ever possible:
struct test_struct
{
explicit test_struct(int size) : array(size) { }
std::vector<int> array;
};
int main()
{
vector <test_struct> data(5, test_struct(5));
return 0;
}
Your solution doesn't work because of test_struct destructor and the fact you're trying to store your structs in a vector.
When test_struct tmp is pushed to the vector, a copy of test_struct is created. Then tmp is destroyed with calling delete[] array and the copy in vector <test_struct> data ends up with a dangling pointer.
You probably need to rethink your architecture, or at least add a copy constructor for the test_struct that will copy the whole array
Related
I try to free the memory correctly after the program ends, but I always encounter a problem.
In my code I want to have an array of all the numbers that I allow in my program, and have objects A and B (or more) that each one have some of the numbers that I allowed.
In the end I want to delete 'a' and 'b' only after "ints" getting out of the scope. But A and B calls their distructors to delete some of ints variables.
#define MAX_LEN 255
class IntArray
{
public:
int len;
void add(int* n) {
arr[len] = n; len++;
}
IntArray() : arr(new int* [MAX_LEN]), len(0) {}
~IntArray() {
for (int i = 0; i < len; i++)
delete arr[i];
delete[] arr;
}
private:
int** arr;
};
class Object
{
public:
void add(int* n) {
myIntArr.add(n);
}
private:
IntArray myIntArr;
};
int main(void)
{
int* a = new int(5);
int* b = new int(6);
IntArray ints;
ints.add(a);
ints.add(b);
Object A;
A.add(a);
Object B;
B.add(b);
return 0;
}
If you want to share dynamically allocated ints between multiple objects, use std::shared_ptr<int>.
Also, rather than writing a dynamic array type yourself, use std::vector to do it (correctly) for you.
using int_ptr = std::shared_ptr<int>;
class IntArray
{
public:
void add(int_ptr n) {
arr.push_back(n);
}
private:
std::vector<int_ptr> arr
};
class Object
{
public:
void add(int_ptr n) {
myIntArr.add(n);
}
private:
IntArray myIntArr;
};
int main(void)
{
int_ptr a = std::make_shared<int>(5);
int_ptr b = std::make_shared<int>(6);
IntArray ints;
ints.add(a);
ints.add(b);
Object A;
A.add(a);
Object B;
B.add(b);
return 0;
}
If you just want to have a copyable array of int, use std::vector<int>.
You're deleting a and b twice.
You should only delete something returned by new and exactly once.
But you add them both to IntArray ints; and then one each to Objects A and B and their destructors delete them also. Destructors are called in reverse order to it's when ints is destructed you'll be deleting them again - that's "Undefined Behaviour" but normally a catastrophic failure (crash) either immediately or later during executon.
The shortest fix is:
int* a = new int(5);
int* b = new int(6);
int *ac = new int(*a);//copy of *a
int *ab = new int(*b);//copy of *b
IntArray ints;
ints.add(a);
ints.add(b);
Object A;
A.add(ac);
Object B;
B.add(bc);
But it's not clear what our intention is. IntArray isn't an array of int as it stands, it's an array of pointers to int (which have been allocated by new).
My 'fix' will mean if you modify a (e.g. *a=20) you won't modify the copy (ac) added to the Object A.
I wonder whether copying a vector I am copying the vector with its values (whereas this is not working with array, and deep copy need a loop or memcpy).
Could you hint to an explanation?
Regards
You are making a deep copy any time you copy a vector. But if your vector is a vector of pointers you are getting the copy of pointers, not the values are pointed to
For example:
std::vector<Foo> f;
std::vector<Foo> cp = f; //deep copy. All Foo copied
std::vector<Foo*> f;
std::vector<Foo*> cp = f; //deep copy (of pointers), or shallow copy (of objects).
//All pointers to Foo are copied, but not Foo themselves
Vector will resize to have enough space for the objects. It will then iterate through the objects and call the default copy operator for every object.
In this way, the copy of the vector is 'deep'. The copy of each object in the vector is whatever is defined for the default copy operator.
In examples... this is BAD code:
#include <iostream>
#include <vector>
using namespace std;
class my_array{
public:
int *array;
int size;
my_array(int size, int init_val):size(size){
array = new int[size];
for(int i=0; i<size; ++i)
array[i]=init_val;
}
~my_array(){
cout<<"Destructed "<<array[0]<<endl;
if(array != NULL)
delete []array;
array = NULL;
size = 0;
}
};
void add_to(vector<my_array> &container){
container.push_back(my_array(4,1));
}
int main(){
vector<my_array> c;
{
my_array a(5,0);
c.push_back(a);
}
add_to(c);
//At this point the destructor of c[0] and c[1] has been called.
//However vector still holds their 'remains'
cout<<c[0].size<<endl; //should be fine, as it copies over with the = operator
cout<<c[0].array[0]<<endl;//undefined behavior, the pointer will get copied, but the data is not valid
return 0;
}
This is BETTER code:
#include <iostream>
#include <vector>
using namespace std;
class my_array{
public:
int *array;
int size;
my_array(int size, int init_val):size(size){
cout<<"contsructed "<<init_val<<endl;
array = new int[size];
for(int i=0; i<size; ++i)
array[i]=init_val;
}
my_array(const my_array &to_copy){
cout<<"deep copied "<<to_copy.array[0]<<endl;
array = new int[to_copy.size];
size = to_copy.size;
for(int i=0; i<to_copy.size; i++)
array[i]=to_copy.array[i];
}
~my_array(){
cout<<"Destructed "<<array[0]<<endl;
if(array != NULL)
delete []array;
array = NULL;
size = 0;
}
};
void add_to(vector<my_array> &container){
container.push_back(my_array(4,1));
}
int main(){
vector<my_array> c;
{
my_array a(5,0);
c.push_back(a);
}
add_to(c);
//At this point the destructor of c[0] and c[1] has been called.
//However vector holds a deep copy'
cout<<c[0].size<<endl; //This is FINE
cout<<c[0].array[0]<<endl;//This is FINE
return 0;
}
I can't seem to understand why my program runs successfully and then crashes at destructor. Below is my main() source code (which is fairly simple, it sends an array of 5 variables to a class template which creates the appropriate type. I did some research and seem to be missing something that might cause a crash because of an additional call of the destructor? I'm a little fuzzled and it's most likely a simple fix.
main.cpp:
int main()
{
// using integer data type
int arraya[5] = { 1, 2, 3, 4, 5 };
GenericArray<int> a(arraya, 5);
a.print();
// using float data type
float arrayb[5] = { 1.012, 2.324, 3.141, 4.221, 5.327 };
GenericArray<float> b(arrayb, 5);
b.print();
// using string data type
string arrayc[] = { "Ch1", "Ch2", "Ch3", "Ch4", "Ch5" };
GenericArray<string> c(arrayc, 5);
c.print();
return 0;
}
header file contents:
#ifndef GENERIC_ARRAY_H
#define GENERIC_ARRAY_H
#include<string>
#include<iostream>
template<typename type>
class GenericArray
{
public:
GenericArray(type array[], int arraySize); // constructor
~GenericArray(); // destructor
void print(); // the print function
GenericArray(const GenericArray &obj); //copy constructor
private:
type *ptr; //new pointer of respective type
int size;
};
template<typename type>//print() function
void GenericArray<type>::print()
{
for (int index = 0; index < size; index++)
{
cout << ptr[index] << " ";
}
cout << endl;
}
template<typename type>//Constructor
GenericArray<type>::GenericArray(type array[], int arraySize)
{
size = arraySize;
ptr = new type[size];
ptr = array;
}
template<typename type>//Destructor
GenericArray<type>::~GenericArray()
{
cout << "Freeing Memory!";
delete[] ptr;
}
template<typename type>//Copy Constructor
GenericArray<type>::GenericArray(const GenericArray &obj)
{
*ptr = *obj.ptr;
}
#endif
-In the print() method:
It isn't safe, that there was memory allocated at memory positions ptr ... (ptr + size - 1), so you might run into a segmentation fault.
-In the constructor:
you allocate memory via new, but then immediately redirect your pointer to point at the same position as array is pointing at. . This means you got a memory leak.
-In the destructor:
As was already mentioned, your program crashes here when the destructor is called, because the delete[] doesn't operate on the memory that was allocated with new, see the constructor remarks.
-In the copy constructor:
There are two problems here. First of all, you can't dereference the lhs-ptr here because there wasn't memory allocated for him. Moreover, if there was memory allocated for ptr, the statement *ptr = *obj.ptr; would just copy the first element of obj.ptr (if there was memory allocated at this position as well) to the first element of ptr.`
The constructors are defined incorrectly. They shall copy elements of source objects.
For example
#include <algorithm>
//...
template<typename type>//Constructor
GenericArray<type>::GenericArray( const type array[], int arraySize )
: ptr( new type[arraySize] ), size( arraySize )
{
std::copy( array, array + arraySize, ptr );
}
template<typename type>//Copy Constructor
GenericArray<type>::GenericArray( const GenericArray &obj )
: ptr( new type[obj.size] ), size( obj.size ),
{
std::copy( obj.ptr, obj.ptr + arraySize, ptr );
}
Also you need to define the copy assignment operator.
I am working with a class I created that has a function addClass which allow the user to add A an Instance of Class to a dynamically allocated array.
Here is the code of the class and a simple test:
Class.h Listing
#ifndef CLASS_H
#define CLASS_H
#include<iostream>
class Class {
public:
Class(std::string text);
Class(const Class& orig);
virtual ~Class();
Class(std::string text, Class * name, int size);
std::string toString();
void addClass(Class * name, int size = 1);
Class getClass(int index);
private:
Class * classArray;
std::string value;
int size;
};
#endif /* CLASS_H */
Class.c Listing
#include "Class.h"
#include <cstdlib>
Class::Class(std::string text) {
classArray = NULL;
value = text;
size = 0;
}
Class::Class(const Class& orig) {/*...*/}
Class::~Class() {}
Class::Class(std::string text, Class * name, int size){
value = text;
this->size = size;
if(size == 1)
classArray = name;
else{
int i;
classArray = (Class*)malloc(size*sizeof(Class));
for(i = 0; i < size; i++){
classArray[i] = name[i];
}
}
}
std::string Class::toString(){
return value;
}
void Class::addClass(Class * name, int size){
int i;
Class * tmp = (Class*)malloc((this->size+size)*sizeof(Class));
for(i = 0; i < this->size-1; i++){
tmp[i] = classArray[i];
}
if(size == 1)
tmp[size-1] = name[0];//assignement method is the problem!!!??
else{
for(i = this->size; i < this->size+size-1; i++){
tmp[i] = name[i];
}
}
this->size += size;
free(classArray);
classArray = tmp;
}
Class Class::getClass(int index){
return classArray[index];
}
test.c Listing
#include<iostream>
#include "Class.h"
using namespace std;
int main(int argc, char** argv) {
Class * objectA = new Class("objectA");
Class * objectB = new Class("objectB");
cout << objectA->toString() << endl;
objectA->addClass(objectB);
//never gets here :'(
cout << objectA->toString() << endl;
return 0;
}
The problem is the test never gets past the objectA->addClass(objectB) instruction. I tried to debug and what I found was that the problem comes from the assignement instruction of the addClass() method. I also tried memcpy it didn't work. Does anyone have a solution for this please. Thanks.
Don't use malloc on C++ objects, use new and new[] and delete and delete[]. The problem with malloc in C++ is that it doesn't call the constructors for your objects, and free doesn't call the destructors. new, new[], delete and delete[] do. You get a crash because you are assigning to unconstructed objects and you get that because you didn't use new.
Not saying that's the only problem with your code, but it's the obvious one.
A basic solution is to prefer new and delete over malloc and free. A much better solution is to use a standard container such as std::vector to hold the elements at Class::addClass(). Let the computer take care of all that memory management; you will be saving a lot of development and debugging time.
Note that in your code you defined a custom copy constructor Class(const Class&) for your class, but you seem not having defined a copy assignment operator Class& operator=(const Class&). Note that in your code you use copy assignment (operator=) to make copies of your class, but you don't have a proper implementation of it.
Moreover, in C++ you should prefer using new[]/delete[] to C's malloc()/free(), and even better just use std::vector container for arrays.
You can also have a std::vector< SomeSmartPointer > (e.g. std::vector<std::shared_ptr<SomeClass>>, or std::vector<std::unique_ptr<SomeClass>>). In general, consider std::vector of some smart pointer, but don't use a std::vector of owning raw pointers (std::vector<SomeClass*>).
say I created a custom Array class and have following constructor:
Array::Array(size_t size)
{
mySize = size;
//myData is of type int*
myData = new int[mySize]; // this stuff is allocated on a heap
}
To my knowledge, a default copy constructor in this case would be implemented like that:
Array::Array(Array& a)
{
mySize = a.mySize;
myData = a.myData; //points to the same memory on the heap
}
Finally, say I have following code in my main.cpp file
int main()
{
Array a(1);
Array b(a); //copy constructor is invoked
}
What I expected to be was a memory leak due to deletion of myData pointers to the free store memory, BUT I have following runtime error :
*** glibc detected *** ./main.out: double free or corruption (fasttop): 0x086ad008 ***
WHY? It seems that ~Array() somehow auto frees memory allocated on a heap - but this is very counter intuitive to me. Maybe I am missing something?
UPDATE:
class Array{
private:
size_t mySize;
int *myData;
...
UPDATE 2:
main.cpp:
#include <iostream>
#include "array.h"
int main()
{
Array a(1);
Array b(a);
}
array.h:
#ifndef ARRAY_H_
#define ARRAY_H_
#include <stddef.h>
class Array{
private:
size_t mySize;
int *myData;
public:
Array(size_t size);
~Array();
void set(int i,int val);
int get(int i);
size_t getSize();
};
#endif
array.cpp:
#include "array.h"
Array::Array(size_t size)
{
mySize = size;
myData = new int[mySize];
}
Array::~Array()
{
delete[] myData;
}
void Array::set(int i, int val)
{
if(i>=0 && i<mySize)
myData[i] = val;
}
int Array::get(int i)
{
if(i>=0 && i<mySize)
return myData[i];
else return -1;
}
size_t Array::getSize()
{
return mySize;
}
I think in your destructor you have
Array::~Array(void)
{
delete [] myData; //points to the same memory on the heap
}
The problem is double free
Example:
int main()
{
Array a(1); // here a.myData = 0x12345678
Array b(a); //copy constructor is invoked // here b.myData = 0x12345678
// pop stack (call destroy of object)
// delete b.myData
// delete a.myData already delete
}
Double free
EDIT:
For your copy contructor use const because you don't modify a.
Array::Array(const Array& a)
{
mySize = a.mySize;
myData = a.myData; //points to the same memory on the heap
}
Good Luck !
So... despite your claims, it turns out you do delete the array in the destructor, and the copy constructor is a shallow copy, so you get a double delete. Simple.
Array::~Array()
{
delete[] myData;
}
Since this is a dynamic array, it should own the data, therefore you are right to delete in the destructor, but you need to "deep" copy in the copy constructor and the assignment operator. See the rule of three.
Your copy is a shallow copy, so IF you have a destructor that frees memory, each object attempts to delete the same memory.
You don't have to do a shallow copy. You could write your own explicit copy constructor that copies the actual data into a newly allocated array.
I like Google's suggestion to disable copy and assignment constructors and prefer explicit CopyFrom() methods.
"double free" means that the same pointer has been given to delete[] twice. because in your destructor (presumably) it's delete[]-ed both in object a and b. practical solution: use std::vector, don’t mess with raw arrays etc. needlessly.
I think your desctructors (from array 'a' and 'b') are trying to free the same memory (double free). Maybe you should check you myData before freeing.