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.
Related
i have a segment fault when it calls the function unit_thread_data,Actually it is caused by ~Data(). thread1 is all right, but thread2 cause the segment fault, the whole code is as fallows:(forgive the poor code style), error info is double free or corruption. Other info: gcc5.4.0, centos7. any help? thank you very much!
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
class Data
{
public:
int* A_;
Data()
{
cout<<"111\n";
A_=NULL;
}
~Data()
{
cout<<"222\n";
if(A_) {
delete A_;
}
}
};
struct thread_data_t
{
Data* d;
};
void* _add(void* _pthread_data)
{
thread_data_t* pthread_data = (thread_data_t*) _pthread_data;
pthread_data->d->A_ = new int[2];
pthread_data->d->A_[0] = 1;
pthread_data->d->A_[1] = 2;
std::cout<<pthread_data->d->A_[0]+pthread_data->d->A_[1]<<endl;
return (void*)0;
}
void unit_thread_data(thread_data_t* pthread_data)
{
for(int i=0;i<2;i++)
{
delete[] pthread_data[i].d->A_;
delete pthread_data[i].d;
}
delete[] pthread_data;
}
int main()
{
int num_threads = 2;
pthread_t threads[num_threads];
thread_data_t* pthread_data = new thread_data_t[num_threads];
for(int i=0;i<num_threads; i++)
{
pthread_data[i].d = new Data();
}
for (int i=0; i<num_threads; i++) {
pthread_create(&threads[i], NULL, _add, (void*)(pthread_data+i));
}
for (int i=0; i<num_threads; i++) {
pthread_join(threads[i], NULL);
}
sleep(1);
unit_thread_data(pthread_data);
return 0;
}
delete[] pthread_data[i].d->A_;
This deletes the A_ member of your Data class, an int *.
Immediately afterwards, this happens:
delete pthread_data[i].d;
And this deletes the Data itself. Data's destructor then does the following:
if(A_) {
delete A_;
}
This then proceeds to attempt delete the same pointer. This should be delete[]d instead of deleted in the first place, but this is moot because this pointer is already deleted, and this tries to delete it a 2nd time.
This results in undefined behavior.
It is because you first delete member A_ here:
delete[] pthread_data[i].d->A_;
without assigning nullptr to A_ afterwards, and then you call delete A_; in the destructor.
Apart from that, in your code it is not clear who should be the owner of the memory allocated under A_ (functions _add and unit_thread_data, or a class itself), hence it is easy to do this kind of mistakes.
Quick fix (not recommended): just remove your destructor's body, and let your external functions _add and unit_thread_data manage the memory.
Better fix (recommended): think about who should be the owner of the allocated data (I would say class Data) and use std::unique_ptr if you can.
You need to assign NULL after deleting A_.
The following function appears in the OctoMap code:
class AbstractOcTreeNode {}; -> They declare an empty class
AbstractOcTreeNode** children; -> This is declared in the OcTreeDataNode class header file
template <typename T>
void OcTreeDataNode<T>::allocChildren() {
children = new AbstractOcTreeNode*[8];
for (unsigned int i=0; i<8; i++) {
children[i] = NULL;
}
}
Wouldn't this cause memory leak? Shouldn't it be:
template <typename T>
void OcTreeDataNode<T>::allocChildren() {
children = new AbstractOcTreeNode*[8];
for (unsigned int i=0; i<8; i++) {
delete children[i];
children[i] = NULL;
}
}
What am I missing? Thanks for the help!
You'd want to delete the entire array, not each of the individual array elements
template <typename T>
void OcTreeDataNode<T>::allocChildren() {
children = new AbstractOcTreeNode*[8];
for (unsigned int i=0; i<8; i++) {
children[i] = NULL;
}
// .... later
delete[] children ;
}
You must always match a new with a delete, and a new[] with a delete[], without mixing them.
For completeness (I'm guessing at the context) since the name of the function is allocChildren I assume it is their intention to new[] the array and not cleanup the memory, yet. Hopefully there would be a matching deallocChildren that would delete[] this memory later.
What is the sense to allocate memory and at once to delete it?
template <typename T>
void OcTreeDataNode<T>::allocChildren() {
children = new AbstractOcTreeNode*[8];
for (unsigned int i=0; i<8; i++) {
delete children[i];
children[i] = NULL;
}
}
The function above does not make sense.
Pay attention to that an empty class has a non-zero size.
And there is allocated an array of pointers to an empty class. Objects of the class are not allocated in this function.
In this function
template <typename T>
void OcTreeDataNode<T>::allocChildren() {
children = new AbstractOcTreeNode*[8];
for (unsigned int i=0; i<8; i++) {
children[i] = NULL;
}
}
the variable children defined in a namespace gets the address of the allocated array in the member function.
So some other code is responsible to free the allocated memory.
In general it is a bad idea that a member function of a class uses a global variable.
AbstractOcTreeNode** children;
children can be seen as an array of pointer values.
children = new AbstractOcTreeNode*[8];
We initialize it with an array of eight pointer values.
for (unsigned int i=0; i<8; i++) {
children[i] = NULL;
}
Each of the eight children[i] pointer values is initially an uninitialized AbstractOcTreeNode*. We assign the NULL value to each of them. Calling delete beforehand on these uninitialized pointers would be Undefined Behavior.
There is only one memory allocation (new[] is only called once), and its result is kept in children. There is no leak as long as children is eventually cleaned up (using delete[], presumably in the destructor of OcTreeDataNode<T>).
Your confusion is the result of having multiple levels of pointers, at least some of which are owning. I personally also find this code hard to read because of that. In modern C++, you would not perform manual memory management, either for allocating the array of pointers (what about std::vector or std::array) or for the allocation of each AbstractOcTreeNode-dervied instance (which is not shown here). You might find std::vector<std::unique_ptr<AbstractOcTreenode>> children; in modern C++ instead.
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;
}
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.
I am attempting to implement a GradeManager class that internally uses an array of DataVector objects that were created dynamically using the new operator, to record the homework grades for a set of students.
I am struggling to make the constructor/destructor.
Description for the constructor: "This is the only constructor of the class, and it specifies the number of students nStudents and number of homeworks nHWs for the class. You should use these to dynamically set the array sizes."
Any thoughts you have to offer will greatly help! This is what I have so far. Thank you so much!!!
#include <iostream>
#include <cmath>
#include <iomanip>
//DO NOT INCLUDE ANYTHING ELSE!!
using namespace std;
typedef double DataType;//Alias for double type
typedef unsigned int UIntType;//Alias for unsigned int type
class DataVector
{
private:
DataType *m_data; //Pointer to dynamically allocated memory that holds all items
UIntType m_size; //Size of the m_data array
public:
DataVector()
{
m_data = new DataType[10];
for(int i = 0; i < 10; i++){
m_data[i]=0;
}
m_size = 10;
}
DataVector(UIntType initSize, DataType initValue)
{
int arraySize = initSize;
m_data = new DataType[arraySize];
for(int i = 0; i < arraySize; i++){
m_data[i] = initValue;
}
m_size = initSize;
}
~DataVector()
{
delete [] m_data;
m_data = NULL;
}
UIntType GetSize()
{
return m_size;
}
void Reserve(UIntType newSize)
{
int arraySize = newSize;
DataType *new_data;
new_data = new DataType[arraySize];
for(int i = 0; i < m_size; i++){
new_data[i] = m_data[i];}
m_data = new_data;
m_size = newSize;
}
};
class GradeManager
{
private:
DataVector *m_student;//m_student[0], m_student[1], etc correspond to sID 0, 1, etc respectively
UIntType m_nStudents;//Number of students
public:
GradeManager(UIntType nStudents, UIntType nHWs)
{
m_student = new DataVector[nStudents];
m_student->Reserve(nHWs);
m_nStudents = nStudents;
}
~GradeManager()
{
int numOfStudents = m_nStudents;
for(int i = 0; i < numOfStudents; i++)
delete [] m_student;
m_student = NULL;
}
};
Some thoughts:
Like stated in the comment by quantdev, use std::vector<> in the DataVector class - much simpler than using an array, though you cannot limit its size directly (as is done nearly-automatically with an array).
It seems you may have a memory leak and possible segmentation fault in DataVector::Reserve(). You allocate the new memory for new_data, copy the data from m_data into new_data (which brings to mind a thought; what happens if m_size is greater than newSize? IMO, a memory access error, but I'm not sure), then re-point m_data to new_data, without releasing the data stored in m_data in previous calls (say, in the constructor). This will lead to a memory leak.
Also, I'm not entirely sure the method DataVector::Reserve() reserves any space, if that's
what it was meant to do.
Also, the constructor/destructor - in my opinion, at least - for GradeManager look fine, with most of the problems located actually in the DataVector class.
Good luck!
I assume that you are not allowed to use the standard containers such as std::vector<> or std::array<> which could facilitate the job.
Your DataVector constructor and destructor are consistent: you create a new dynamic array and your delete the dynamic array.
However inbetween, there is the function Reserve() that you call in GradeMaster constructor.
Its for loop can go out of bounds, because the new size can be bigger or smaller than the old one. You have to check that i remains in bound of both source and target:
for (int i = 0; i < m_size && i<arraySize; i++){ // check on source and target bounds !!!
Also you create memory leak by not releasing the old objects that you do not need anymore. You have to insert this line after the end of your loop:
delete[] m_data; // insert this to avoid memory leaks
A last point is int the GradeMaster destructor. As you delete the whole array with delete[] you MUST NOT loop and try to delete the array several times ! Deleting the array, will delete all its elements. Just remove the for line.