I have a class containing a member pointer which is dynamically allocated in its constructor as follows:
class Record {
public:
Record(unsigned short numBytes, char* bufRecord);
~Record();
unsigned short size() {return m_numBytes;}
private:
unsigned short m_numBytes;
char* m_bufRecord;
};
Record::Record(unsigned short numBytes, char* bufRecord) {
m_numBytes = numBytes;
m_bufRecord = new char[numBytes];
for(unsigned short i=0; i<numBytes; i++)
m_bufRecord[i] = bufRecord[i];
}
Record::~Record() {
delete m_bufRecord;
}
It basically copies the input buffer into the dynamically allocated member buffer. I proceed to use this class as follows, in the constructor of another class:
class File {
public:
File(const char* fileName);
~File();
unsigned int numRecords() {return m_records.size();}
Record getRecord(unsigned int numRecord) {return m_gdsRecords[numRecord];}
private:
std::ifstream m_file;
std::vector<Record> m_records;
};
File::File(const char* fileName) : m_file(fileName, ios::in | ios::binary) {
while(!m_file.eof()) {
char bufNumBytes[2];
char* bufRecord;
unsigned short numBytes;
m_file.read(bufNumBytes, 2);
numBytes = (bufNumBytes[0] << 8) + bufNumBytes[1] - 2;
bufRecord = new char[numBytes];
m_file.read(bufRecord, numBytes);
Record record(numBytes, bufRecord);
m_records.push_back(record);
delete bufRecord;
}
}
However, when I instantiate this class, I get the following error, which seems to state that I'm double-freeing the m_bufRecord:
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001cb3280 ***
I'm guessing the problem lies with the insertion of a class containing a pointer to the vector element, and the destructor being called twice on the same pointer but I'm not sure how this happens. What am I doing wrong here?
This is a case of the Rule of three. If your class needs to free resources in the destructor, it generally needs to declare a copy constructor (and copy assignment operator), to either copy the owned resource, manage shared ownership or prevent being copied.
Record getRecord(unsigned int numRecord) {return m_gdsRecords[numRecord];}
This function returns a copy of the Record. So now you have two Records containing the same m_bufRecord pointer. Running the destructors on these Records will try to delete the same pointer value twice.
Related
Following my understanding of C++ convention, I have:
class BlockRepresentation : public FPRepresentation
{
private:
class Block
{
public:
int id;
int fpDimensions;
int* position; // pointers in question
int* blockDimensions; // pointers in question
~Block();
};
std::vector<Block> all_blocks;
public:
BlockRepresentation( int count, int dimensions, int volumn[] );
void AddBlock( int id, int position[], int dimensions[] );
std::string ToGPL();
};
where new blocks are created in AddBlock:
void BlockRepresentation::AddBlock( int id, int position[],
int dimensions[] )
{
Block newBlock;
newBlock.id = id;
newBlock.fpDimensions = fpDimensions;
newBlock.position = new int[fpDimensions]; // pointers in question
newBlock.blockDimensions = new int[fpDimensions]; // pointers in question
for (int i = 0; i < fpDimensions; ++i)
{
newBlock.position[i] = position[i];
newBlock.blockDimensions[i] = dimensions[i];
}
all_blocks.push_back( newBlock );
}
so I have the following destructor:
BlockRepresentation::Block::~Block()
{
delete[] position;
delete[] blockDimensions;
}
but then I get:
rep_tests(11039,0x7fff71390000) malloc: *** error for object 0x7fe4fad00240: pointer being freed was not allocated
Why should I not delete[] the 2 pointers here?
As was pointed out in the comments, you violated the rule of three, and the violation is very obvious:
{
Block newBlock;
// snip
all_blocks.push_back( newBlock );
}
When this function returns, the newBlock object goes out of scope, and its destructor will delete all the newed arrays.
But you push_back()ed this object. This constructs a copy of the object into the vector. Because your Block does not define a copy constructor, the default copy-constructor simply makes a copy of all the pointers to the newed arrays.
If you somehow manage to avoid dereferencing the no-longer valid pointers, or you survived that experience, you're not of the woods yet. That's because, when the vector gets destroyed, and its Blocks get destroyed, their destructors will, once again, attempt to delete the same newed arrays that were already deleted once before.
Instant crash.
There is nothing wrong with your Block destructor. It is doing its job, which is releasing the memory that is pointed to by your two int * member variables. The problem is that the destructor is being called on the same pointer value multiple times, which results in a double-free error.
The entity that causes this is the std::vector<Block>, since a std::vector will make copies of your Block object, and your Block object is not safely copyable.
Since the member variables of Block that are pointers are position and blockDimensions, the most painless way to alleviate this issue is to use std::vector<int> instead of int *, as demonstrated by this sample program.
However, if you really wanted to use int *, you would need to implement a user-defined copy constructor. In addition, a user-defined assignment operator would complement the copy constructor. This is what is called the Rule of Three.
#include <algorithm>
//...
class Block
{
public:
int id;
int fpDimensions;
int *position;
int *blockDimensions;
Block() : position(nullptr), blockDimensions(nullptr),
id(0), fpDimensions(0) {}
~Block()
{
delete [] position;
delete [] blockDimensions;
}
Block(const Block& rhs) : id(rhs.id), fpDimensions(rhs.fpDimensions),
position(new int[rhs.fpDimensions]),
blockDimensions(new int[rhs.fpDimensions])
{
std::copy(rhs.position, rhs.position + fpDimensions, position);
std::copy(rhs.blockDimensions, rhs.blockDimensions + fpDimensions,
blockDimensions);
}
Block& operator=(const Block& rhs)
{
Block temp(rhs);
std::swap(temp.position, position);
std::swap(temp.blockDimensions, blockDimensions);
std::swap(temp.id, id);
std::swap(temp.fpDimensions, fpDimensions);
return *this;
}
};
See the live sample here.
See all of the hoops we had to jump through to get the Block class to behave correctly when used within a std::vector, as opposed to simply using std::vector<int>?
I have tried to read lots of solutions to memory leaks occur in copy constructor, but i still didnt understans how to solve it.
For example i have a "Person" class that has those mambers and functions (header files):
#include "Object.h"
#include <string.h>
#include <iostream>
using namespace std;
class Person: public Object
{
private:
char * p_name;
int length;
public:
virtual Object * copy() const;
virtual void print(ostream & os) const;
Person(char * name);
Person(const Person & per);
~Person();
};
In this program Im trying to enter "Objects" to a Vector while Person and Vector inherit from Object.
In both of the copy const i have memory leak problems (the program is working excellent).
For example in this code im getting a memory leaks of all of those 5 char arrays. I have more problems also in Vector memory leaks, but lets start in this simple code in the main (that occurs 5 memory leaks of the char array):
int main ()
{
const int SIZE = 5;
Person* persons[SIZE];
int i;
// preparation of name array
for (i = 0; i<SIZE; i++) {
char* tmp = new char[10];
sprintf(tmp, "P-%d", i);
persons[i] = new Person(tmp);
}
for (i = 0; i < SIZE; i++)
delete persons[i];
return 0;
}
Person class is:
#include "Person.h"
using namespace std;
Object * Person::copy() const
{
Person * p = new Person(*this);
return p;
}
void Person::print(ostream & os) const
{
for (int i = 0; i < this->length-1; i++)
{
os << this->p_name[i];
}
}
Person::Person(char * name)
{
delete this->p_name;
this->length = strlen(name)+1;
p_name = new char[length];
strncpy(p_name, name, length);
}
Person::Person(const Person & per)
{
delete[] this->p_name;
this->length = strlen(per.p_name) + 1;
this->p_name = new char[this->length];
strncpy(this->p_name, per.p_name, this->length);
}
Person::~Person()
{
delete[] this->p_name;
}
I would be thankful for your help!!
In main(), the tmp char array is not deleted, and that's the first memory leakage I'm seeing.
In the Person(char * name) constructor you call a delete on
Person::Person(char * name)
{
delete this->p_name;
the p_name is not allocated, so the behavior is undefined. And p_name is an array, so delete[] should be used.
if you use the std::string class, you can at least avoid the confusion between delete and delete[]
You don't have just a memory leak. You have a full-fledged, memory-corrupting, undefined behavior:
Person::Person(char * name)
{
delete this->p_name;
This is your constructor. The p_name class member does not appear to be initialized in any way. And the first thing you do, is you try to delete it.
So, whatever random value p_name will contain, as a result of the most recent set of cosmic rays striking the RAM capacitors that hold its initial value, the first thing the constructor does is try to free the pointed-to memory.
Before you can worry about any alleged leaks from your copy constructor, you need to fix a bunch of problems, like this, elsewhere.
in main(), where you prepare your c you allocate 5 char buffers, that're never freed
also (not speaking of std::string which would help you with your string stuff) , get rid of the unneeded "this->"s:
Person::Person(const Person & per)
{
delete[] this->p_name;
this->length = strlen(per.p_name) + 1;
this->p_name = new char[this->length];
strncpy(this->p_name, per.p_name, this->length);
}
could look like this:
Person::Person(const Person & per)
{
delete[] p_name;
length = strlen(per.p_name) + 1;
p_name = new char[length];
strncpy(p_name, per.p_name, length);
}
There are some problems with delete.
In your main, in the first while you have to delete temp; in the second well just don't use it, use delete [] persons.
In your copy constructor don't use delete this->p_name, that's not correct.
At first you have to set the pointer to null so p_name=NULL, and then use setters and getters, same for your value constructor.
And in your destructor, test if p_name exists before deleting it.
I am trying to make a deep copy (for copy on write) of an object but I get a segmentation fault.
I am using a hashtable with linked list.
class Person
{
public:
Person(const char * id,int nb)
{
this->id=strdup(id);
this->nb=nb;
this->init=init;
this->next=NULL;
}
Person(const Person& rhs) :
nb(rhs.nb),
init(rhs.init),
id(strdup(rhs.id)),
next(rhs.next == NULL ? NULL : new Person(*rhs.next)) {}
char* strdup(char const* in)
{
char* ret = new char[strlen(in)+1];
strcpy(ret, in);
return ret;
}
int nb,init;
const char * id;
Person *next;
};
Hashtable deepcopy (const Hashtable& rhs)
{
num[0]=num[0]-1;
Person** array=rhs.table;
Hashtable autre;
for (int i = 0 ; i < size; ++i)
if (autre.table[i]!=NULL)
autre.table[i] = new Person(*array[i]);
return autre;
num[0]=1;
}
the attributs of my class Hashtable:
Person **table;
int* num;
EDIT: this problem seem to be fixed.
What is wrong with my deep copy? I don't understand. I think that my copy constructor is good but I don't understand why I get a seg fault when I run it.
This code must be fixed:
for (int i = 0 ; i < size; ++i)
autre.table[i] = new Person(*array[i]);
table has fixed size, and it's filled with null-pointers. In your loop, you don't check if the element to be copied is a null-pointer, so you derefence it and try to copy the entity which even doesn't exist.
for (int i = 0 ; i < size; ++i) {
if(array[i] != NULL) {
autre.table[i] = new Person(*array[i]);
}
}
PS: It's better to use nullptr instead of NULL.
Problems that I see:
Default constructor of Person.
Person(const char * id,int nb)
{
this->id=id;
this->next=NULL;
}
If I use
Person foo()
{
char id[] = "John";
return Person(id, 0);
}
Person a = foo();
Then the stack memory used for holding "John" in foo is now held on to by a, which will lead to undefined behavior.
You need to take ownership of the input string. Use std::string for id instead of char const*.
Copy constructor of Person.
The statement
id(rhs.id),
will be a problem if you decide to use char const* as type for id. If you switch it to std::string, it won't be a problem.
Copy constructor of HashTable makes a shallow copy of table. This will be a problem if you decide to delete the table in the destructor of HashTable. If you don't delete table in the destructor of HashTable, you have a memory leak.
In deepcopy, you are not checking whether array[i] is NULL before dereferencing it. This has already been pointed out by #alphashooter. Additionally, you are creating a deep copy in a local variable of the function,autre. The deep copy is not visible outside the function unless you return autre from it.
EDIT
Since you are not allowed, to use std::string, you will have to allocate memory for the char const* in the default constructor as well as the copy constructor. If your platform has the non-standard function strdup and you are allowed to use it, you can change the default constructor to:
Person(const char * id,int nb)
{
this->id=strdup(id);
this->next=NULL;
}
You need to make a similar change to the copy constructor.
If you don't have strdup or you are not allowed to use it, you can define it. It's a very simple function to write.
char* strdup(char const* in)
{
char* ret = new char[strlen(in)+1];
strcpy(ret, in);
return ret;
}
I have a simple class:
class Histogram {
int m_width;
int m_height;
int m_sampleSize;
int m_bufferWidth;
int m_bufferHeight;
uint8* m_buffer;
int m_size;
public:
Histogram() : m_buffer(0) { }
Histogram(int width, int height, int sampleSize) {
m_buffer = new unsigned char [width*height*sampleSize];
}
~Histogram() {
my_log("destructor: buffer: %p", m_buffer);
if ( m_buffer ) { delete [] m_buffer; m_buffer = NULL; }
}
unsigned char* buffer() {
return m_buffer;
}
};
It is a member in other class:
class Other {
Histogram m_histogram;
void reset() {
my_log("reset() called: buffer: %p", m_histogram.buffer());
m_histogram = Histogram(512, 512, 2);
}
}
Now, I first create "uninitialized" object using Histogram() constructor – which sets m_buffer to NULL;
Then, I call the reset method, which does m_histogram = Histogram( 512, 512, 3 ) – the new object has m_buffer initialized via new.
So expected sequence of log messages is:
"reset() called: buffer: 0x0"
"destructor: buffer: 0x0"
But instead, I get:
"reset() called: buffer: 0x0"
"destructor: buffer: 0x072a7de"
So some irrational action is being performed. Moreover, the 0x072a7de address is displayied when I also delete the second object (created with "larger" constructor, with three int parameters).
You MUST realize copy-ctor and assignment operator for your class Histogram, since
m_histogram = Histogram(512, 512, 2);
is assignment operator call. Implicit operator = bitwise copy members of your class.
And you must use delete[] in destructor, not delete, since you allocate an array.
First of all, since you are pointing to a dynamically allocated array, you need to use operator delete[]
delete[] m_buffer;
Second, and more importantly, since you have dynamically allocated memory, you should follow the rule of three and implement a copy constructor, and assignment operator, as well as fixing the destructor.
What happens now is that your (compiler synthesized) assignment operator is making a "shallow" copy, i.e. it is copying the pointer. Then you will hve multiple destructors trying to delete it. You are invoking undefined behaviour.
You could really save yourself a lot of trouble by using an std::vector<uint8> as a buffer.
I am attempting to dynamically allocate memory to the heap and then delete the allocated memory. Below is the code that is giving me a hard time:
// String.cpp
#include "String.h"
String::String() {}
String::String(char* source)
{
this->Size = this->GetSize(source);
this->CharArray = new char[this->Size + 1];
int i = 0;
for (; i < this->Size; i++) this->CharArray[i] = source[i];
this->CharArray[i] = '\0';
}
int String::GetSize(const char * source)
{
int i = 0;
for (; source[i] != '\0'; i++);
return i;
}
String::~String()
{
delete[] this->CharArray;
}
Here is the error I get when the compiler tries to delete the CharArray:
0xC0000005: Access violation reading location 0xccccccc0.
And here is the last call on the stack:
msvcr100d.dll!operator delete(void * pUserData) Line 52 + 0x3 bytes C++
I am fairly certain the error exists within this piece of code but will provide you with any other information needed. Oh yeah, using VS 2010 for XP.
Edit: Heres my String.h
// String.h - string class
#pragma once
#define NOT_FOUND -1
class String
{
public:
String();
String(char* source);
static int GetSize(const char * source);
int Find(const char* aChar, int startPosition = 0);
~String();
private:
char* CharArray;
int Size;
};
Change your default ctor; given the error you're getting, the delete call is trying to delete a pointer that has never been initialized.
String::String() : Size(0), CharArray(NULL) {}
Also, beware of the "copy constructor". You might want to make it private just to be sure you're not triggering it implicitly. (It doesn't need to be implemented if you don't intend to call it, just stick the function prototype into your class definition.) Might as well similarly "disable" the assignment operator.
class String
{
// other stuff
private:
String(String&);
String& operator=(String&);
};
This addition fulfills the "Rule of Three," which says that if any class needs a destructor, a copy constructor, or an assignment operator, it probably needs all three.
Edit: see http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
String::String(): CharArray( 0 ) {}
You're not initializing CharArray in every constructor, so in some cases you're deleting an uninitialized pointer.
You have multiple constructors, but only 1 of them calls new. Your destructor always calls delete so there is your error.
I think #dash-tom-bang is correct. You're probably copying String and then deleting its data twice. I'll keep my old answers here for reference, though.
You're going to need to post the code that uses String, but I can notice a few problems here:
What if source is NULL in the constructor? Immediately you have a Null Pointer Exception. What's worse, if you get this exception, the destructor will attempt to delete memory that was never allocated. This could cause the error described above if you're using try...catch.
GetSize should not be a member function of String because it doesn't use any member variables. At the very least it should be static.