Right usage of destructor - c++

I just started working with C++ and now I have a really basic question.
I wrote 2 classes:
Coordinate:
#include <stdio.h>
class Coordinate {
private:
int x;
int y;
public:
Coordinate(int a, int b) {
x = a;
y = b;
};
void printTest() {
printf("%d %d\n", x, y);
};
};
Test:
class Test {
private:
int q;
Coordinate *point;
public:
Test(int a, int b, int c) {
q = a;
point = new Coordinate(b, c);
};
virtual ~Test() {
delete point;
}
};
main function:
int main() {
Test *test = new Test(1, 2, 3);
// ...
delete test;
return 0;
}
In my main I worked with an object of the Test class. I wrote my own Test destructor but I am not sure if this destructor work like expected. Does it completly deallocte the memory from test? Or do I have to do something with the q attribute to deallocate it?

What you've done is correct, as far as it goes. Valgrind reports
==28151== HEAP SUMMARY:
==28151== in use at exit: 0 bytes in 0 blocks
==28151== total heap usage: 3 allocs, 3 frees, 72,736 bytes allocated
==28151==
==28151== All heap blocks were freed -- no leaks are possible
What you're missing is that the compiler has provided you with a default copy constructor and assignment operator. These will copy the pointer, rather than creating a new pointed-to value, so any time you copy a Test object you will then have two objects whose destructors will both try to delete the same storage. That's a double-free, and it can ruin your day.
To avoid that, C++ programmers use the Rule of Three or Rule of Five when writing classes, or - even better - the Rule of Zero, which says you shouldn't do any new or delete except in a class that exists only to own the storage.

Yes, this is the correct usage of a C++ destructor (your destructor in Test does not need the virtual keyword as there is no inheritance in your example).
As a rule of thumb every new should be followed by a delete, but when you're using class and instantiation it becomes more subtle than that. Following the Rule of Three or Five, when a class uses dynamic memory you should redefine the class destructor to deallocate accordingly, which you did, so great!
In your program execution, when delete test is invoked it will first deallocate the dynamic memory of point, before deallocating the dynamic memory you set in your main function with your test attribute. In this way you're not leaking memory (yay!) and your memory management has been done accordingly :)

You need a copy constructor to be sure that memory management is doing ok.
Because implicitly-generated constructors and assignment operators simply copy all class data members ("shallow copy").
And since you have pointers in your class with allocated data you really need it.
For example if in your part of main code: // ... you do a copy like:
Test testB = *test;
testB has a Coordinate pointer that is pointing to the same memory area that *test. It could cause problems, for example, when testB goes out of scope, it will free the same memory that *test is using.
Copy constructor should look like:
Test(const Test& other)
: point (new Coordinate(other.x, other.y))
, q(other.q)
{
}
With this you will be sure that every Coordinate* is initializated ok and released ok.

In your case, you don't need pointer
class Test {
private:
int q;
Coordinate point;
public:
Test(int a, int b, int c) : q(a), point(b, c) {};
};
int main() {
Test test(1, 2, 3);
// ...
return 0;
}
Would be enough.
If you want to allocate memory, I strongly suggest to use smart pointer or container instead:
class Test {
private:
int q;
std::unique_ptr<Coordinate> point;
public:
Test(int a, int b, int c) : q(a), point(std::make_unique_ptr<Coordinate>(b, c)) {};
};
int main() {
auto test = std::make_unique<Test>(1, 2, 3);
// ...
return 0;
}
In both way, you respect rule of 3/5/0.
In second case, you should probably want to provide copy constructor to your class:
Test(const Test& rhs) : q(rhs.q), point(std::make_unique<Coordinate>(*rhs.point)) {}

Related

How to observe c++ destructor destroys basic data types?

I have two classes one is main and other is Test, for the Test class, I have Test.cpp and Test.h
//-----Test.h--------//
#pragma once
class Test
{
private:
int num;
public:
Test(void);
Test(int n);
~Test(void);
};
//------Test.cpp------//
#include "Test.h"
#include<iostream>
using namespace std;
Test::Test(void)
{
}
Test::Test(int n)
{
num = n;
}
Test::~Test(void)
{
cout << "Deleted" << endl;
cout << "num = " << num << endl ;
}
//---------main.cpp--------------//
#include "Test.h"
#include<iostream>
using namespace std;
int main()
{
Test t1 = Test(5);
return 0;
}
The output which I have expected is
Deleted
num = 0
But Real Output is
Deleted
num = 5
Why this occurs, why destructor, dint free the memory
or dint delete the basic data type, How can I delete the variable,
Using what method I can observe basic datatype getting deleted?
Destruction of an object does not mean setting values to zero. That would be unnecessary work. Rather, all that is required is that resources be released. Bits are typically left as-is (representing 5 in your example) unless there is a compelling reason to do otherwise.
Furthermore, members are destroyed after the class. In your example, first ~Test() is run to destroy t1, then t1.num would be destroyed. The destructor of Test cannot view the destruction of Test::num.
why destructor, dint free the memory or dint delete the basic data type
You did not have any memory allocated in the heap, so there is no need to free anything.
All you have is a basic type int which does not need any memory deallocation.
If instead you had some pointer member variable:
private:
int* num;
and you allocated it somewhere in your constructor: new int(6); then sure you must deallocate/free it inside your destructor.
In this case, probably a shared-pointer may help, which automatically is destroyed just after the destructor:
std::shared_ptr<int> num;
But it has to be constructed, in the constructor you need:
Test::Test(int n)
: num(std::make_shared<int>(n)
{
// *n == 100
}
To see if the data is deleted use Valgrind.

Creating a dynamical array of objects in the constructor of a different class

I have a headache. Is the following code snippet right? I would like to create an array of 19 B objects, which contains another array of X A objects. (X is variable, I mean that the As array could vary in length between the B objects)
Later on I would like to say something like B_obj[i].As[j].number = 0;
(i = [0-18], j = [0 - depends on the object])
Example:
class A
{
public:
A();
private:
char *arena;
size_t size;
int number;
};
A::A()
{
size = 5;
arena= (char *) malloc (size);
... some code ...
}
class B
{
private:
int counter;
A* As;
public:
B();
};
B::B()
{
counter = getMyNumber(); /* getMyNumber returns an individual ID */
As= (A*) malloc(counter * sizeof(A)));
}
B B_obj[19];
Is the memory correct allocated? Everything have to be setup, I am not allowed to alloc extra memory later on.
I would like to create an array of 19 B objects, which contains another array of X A objects.
class B {
std::vector<A> x;
public:
// your public interface here
};
B arr[19];
The solution becomes very simple when you use good RAII solutions like std::vector, because it does the memory management for you. Memory is allocated automatically, and you can use std::vector::reserve to allocate a certain number of A objects in the vector.

`delete[]` on `int*` allocated with `new` gives malloc error

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>?

Appropriate destruction of certain class members

I have a class with several pointer members that can be reallocated. When I use the LoadOBJ() function, I'm supposed to replace the already held data but I'm having trouble with garbage collection. Below is some code.
class Object3d{
public:
int nVertex;
int nFace;
int nVertexNormal;
Vector3d *vertex;
Vector3d *vertexNormal;
Face3d *face;
void LoadOBJ(char*);
Object3d():nVertex(0), nFace(0), vertex(NULL), face(NULL){}
Object3d(char*);
~Object3d(){}
};
Face3d:
struct Face3d{
int nFaceV;
int *iVertex;
int *iVertexNormal;
Face3d():nFaceV(0){}
};
Everytime I load a new object with the LoadOBJ() function, I want to delete the previously allocated memory, rather than just use new and leak previously allocated memory.
I'm not sure how to do this. This is what I thought of for now:
void *vGarbage, *vGarbage2,
*fGarbage,
*iGarbage, *iGarbage2;
//nFace is the previous number of faces; in the case of a new object, it's 0
for(int i=0; i<nFace; i++)
{
iGarbage=face[i].iVertex;
iGarbage2=face[i].iVertexNormal;
delete[] iGarbage;
delete[] iGarbage2;
}
vGarbage=vertex;
fGarbage=face;
vGarbage2=vertexNormal;
delete[] vGarbage;
delete[] vGarbage2;
delete[] fGarbage;
The above code runs everytime I use LoadOBJ(), but there still is memory leak. I'm also wondering if this is the right way to do it?
To clarify where the problem/question is: why do I still have memory leak? And, is there better/cleaner way to delete the previously allocated memory?
Check out C++11's smart_pointers, they provide the ability of allocating memory which, when the object goes out of scope, will be freed automatically.
#include <memory>
#include <iostream>
struct Foo {
Foo() { std::cout << "Foo...\n"; }
~Foo() { std::cout << "~Foo...\n"; }
};
struct D {
void operator()(Foo* p) const {
std::cout << "Call delete for Foo object...\n";
delete p;
}
};
int main()
{
{
std::cout << "constructor with no managed object\n";
std::shared_ptr<Foo> sh1;
}
{
std::cout << "constructor with object\n";
std::shared_ptr<Foo> sh2(new Foo);
std::shared_ptr<Foo> sh3(sh2);
std::cout << sh2.use_count() << '\n';
std::cout << sh3.use_count() << '\n';
}
{
std::cout << "constructor with object and deleter\n";
std::shared_ptr<Foo> sh4(new Foo, D());
}
}
Output:
constructor with no managed object constructor with object Foo... 2 2
~Foo... constructor with object and deleter Foo... Call delete for Foo
object... ~Foo...
(http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr)
Remember that for each new a delete should be called when freeing memory. Local pointers can be dangerous if they get destroyed and you didn't free memory before that point.
The RAII paradigm in object-oriented C++ has been designed specifically to make resource management (and also memory management) easy.
If disaster has already been done, you can clean your code up with something like http://deleaker.com/ or equivalent memory leak-seeker software.
Also: if you can't use C++11 or you can't use a C++11-supporting compiler, take a chance of implementing smart pointers yourself, it shouldn't be too hard and will surely help your memory problems.
I understand you want to free the memory occupied by Object3d::vertex, Object3d::vertexNormal and Object3d::face before reasigning these members. First, you should provide a custom destructor for your Face3d so that you no longer need to care for it's members in the containing class. That is:
face3d::~face3d() {
if (iVertex) delete[] iVertex;
if (iVertexNormal) delete[] iVertexNormal;
}
In your Object3d class, you can use a dedicated clean-up function:
void Object3d::cleanup() {
if (face) delete[] face;
face = nullptr;
if (vertex) delete[] vertex;
vertex = nullptr;
if (vertexNormal) delete[] vertexNormal;
vertexNormal = nullptr;
nVertex = 0;
nFace = 0;
nVertexNormal = 0;
}
Btw, In the destructor Object3d::~Object3d() you must call that function as well.
This question might answer yours. I think that you have to cast the void pointer to a specific one, like int*, to make it work. But the behaviour is highly dependent of the compiler you use.
edit: the advice of using smart pointers is probably the easiest and safest way of solving your problem.
Use std::vector instead of manually managed arrays:
struct Face3d{
int nFaceV;
std::vector<int> iVertex;
std::vector<int> iVertexNormal;
Face3d():nFaceV(0){}
};
class Object3d{
public:
std::vector<Vector3d> vertex;
std::vector<Vector3d> vertexNormal;
std::vector<Face3d> face;
void LoadOBJ(char*);
Object3d():nVertex(0), nFace(0), vertex(NULL), face(NULL){}
Object3d(char*);
~Object3d(){}
};
This frees you from the burden to write destructors. As already said above, this is exemplifies the RAII pattern in C++ which should be used instead of manual resource management.
As a general comment, public data members are almost always a bad idea because it breaks encapsulation. Object3d should provide some services to clients and keep its internal private.

Using malloc/free to simulate new/delete

I created an example classes (only for learning purposes) which don't have to use constructor initialization lists because I want to get the same effects using new/delete and malloc/free. What are other constraints besides not using constructor initialization list? Do you think that the following code simulate the new/delete behavior in the right way?
#include <iostream>
using namespace std;
class X
{
private:
int* a;
public:
X(int x)
{
this->a = new int;
*(this->a) = x;
}
~X() { delete this->a; }
int getA() { return *(this->a); }
};
class Y
{
private:
int* a;
public:
void CTor(int x)
{
this->a = new int;
*(this->a) = x;
}
void DTor() { delete this->a; }
int getA(){ return *(this->a); }
};
void main()
{
X *xP = new X(44);
cout<<xP->getA()<<endl;
delete xP;
Y *yP = static_cast<Y*>(malloc(sizeof(Y)));
yP->CTor(44);
cout<<yP->getA()<<endl;
yP->DTor();
free(yP);
system("pause");
}
Without using delete xP, destructor will be called automatically when program ends, but a free store won't be freed (i.e. free store for xP, free store for field a will be freed) . When using delete xP destructor is called and then a free store is completely freed.
Please correct me if I'm wrong.
The actual answer to your question is that you are incorrect, not calling delete xP will lead to a memory leak. It is very likely that the OS then cleans up the memory for you, but it's not GUARANTEED by the C++ runtime library that this happens - it's something that OS's generally offer as a nice service [and very handy it is too, since it allows us to write imperfect code and have code that does things like if (condition) { cout << "Oh horror, condition is true, I can't continue" << endl; exit(2); } without having to worry about cleaning everything up when we've got something that went horribly wrong].
My main point, however, is that this sort of stuff gets very messy as soon as you add members that in themselves need destruction, e.g.
class X
{
private:
std::string str;
...
};
There is no trivial way to call the destructor for str. And it gets even worse if you decide to use exceptions and automated cleanup.
There are many subtle differences that distinguish new from malloc and delete from free. I believe they are only equivalent if the class is POD type.
I should warn that you can never mix the two types freely. A new must always be balanced by a delete and never by a free. Similarly malloc must be balanced only by free. Mixing the two results in undefined behaviour.