c++ malloc and free object creation and deletion - c++

I will first post my test program in C++ :
#include <iostream>
using namespace std;
class X
{
int x;
public:
X()
{
cout<<"constructing\n";
x=0;
}
int& getx()
{
return x;
}
~X()
{
cout<<"destroying\n";
}
};
int main()
{
X* p=(X*)malloc(sizeof(X));
++p->getx();
p->getx()*=5;
cout<<p->getx();
free(p);
return 0;
}
Output :
5
Now before anyone complains why i used malloc & free in a C++ program, I would like to reiterate that it is just a test program and the above could have been done even with operator new & operator delete. But my questions still remain the same that are:
Even though no object of X is created using malloc or operator new how can we access the class X's variable x ?
Clearly free & operator delete also do not destroy the objects and perform mere dallocations. What would happen if I create an object with new but use operator delete or free instead of delete ? Would my object still be there & will it be still usable ?

If you deallocate an object created with new by calling free(), you are deep into undefined behavior. Likewise, if you deallocate a malloc()'ed object with delete, you have undefined behavior. Whatever you do, never mix the two.
malloc() has different semantics than new: malloc() just allocates the memory, it does not call a constructor. new does the allocation, and also calls the appropriate constructor.
Likewise, there is the analogue difference between free() and delete: delete calls the destructor before freeing the memory, free() does not.
You can use malloc() in C++ to back a true C++ object, but you will have to do the constructor/destructor calls yourself:
//The placement-new below needs this:
#include <new>
//This is what new does:
char* temp = (char*)malloc(sizeof(Foo)); //allocation only
Foo* foo = new(temp) Foo(); //placement-new: construction only
//This is what delete does:
foo->~Foo(); //destruction only
free((void*)foo); //deallocation only
Note that the placement-new syntax in the second line is the only way to explicitly call a constructor in C++. The destructor can be called explicitly just like any other member. The reason for this asymmetry is that the object really is a valid object before destruction, which is not the case before construction.
To your question about why p->getx() compiles. That comes down to this little cast in your code:
X* p=(X*)malloc(sizeof(X));
^
|
this little cast
Here you, the programmer, are explicitly telling the compiler: "I know that the value I'm giving you does not look like a pointer to X, but I tell you that it is. So, stupid compiler, just shut up about the type mismatch, and treat it as a pointer to X anyway, because I, the human, your god, told you so!"
So what can your compiler do? It shuts up about the type mismatch, and treats the pointer as a pointer to X, as you told it. If that's wrong, that's your problem. Maybe the program will run fine anyway, maybe it crashes, maybe it silently corrupts data, maybe a pink elephant appears. Your compiler won't care. It's only care is that it did your wish. Compilers can be very obedient.

Answering this part of the question: "What would happen if I create an object with new but use operator delete or free instead of delete ? Would my object still be there & will it be still usable ?"
Allocating with malloc and freeing with delete is undefined behavior. There is no guarantee that the implementation will use C's free after calling the object's destructor.
Likewise the opposite. If you allocate with new, there is no guarantee that the returned pointer came from an internally called malloc, realloc or calloc, only cases that it would be safe to pass the pointer to free.
Even if it works, it may break the program and/or leak resources, because you would either skip object's constructor or destructor.
EDIT:
You said "Clearly free & operator delete also do not destroy the objects and perform mere dallocations." Well, that is wrong. delete will call object's destructor, so it will destroy and then deallocate.
As for the clarified question in comments, for "why can you still access x", well, malloc will allocate the full space occupied by the object (which, in your case, I believe to be just the x variable), and the variable will be there, only the constructor will not be called, so, its value will not be set to zero. If it was initially zero when you ran the program, it was merely a coincidence.

Reading so many points from so many I myself wrote a program to explain your problem. See below :-
#include <iostream>
#include <vector>
using namespace std;
class X
{
int x;
vector<int> v;
public:
X()
{
cout<<"constructing\n";
x=0;
v.push_back(1);
v.push_back(2);
}
int& getx()
{
return x;
}
vector<int>& getv()
{
return v;
}
~X()
{
cout<<"destroying\n";
}
};
int main()
{
X* p=(X*)operator new(sizeof(X));
++p->getx();
p->getx()*=5;
cout<<p->getx()<<"\n";
for (int x:p->getv())
cout<<x<<" ";
cout<<"\nexecuted\n";
operator delete(p);
return 0;
}
/* Output :-
5
executed
*/
See how p ignored the vector v and went for the line executed. This is because vector<int> being a class (or more precisely a class template) was never created by operator new (or malloc in your case). Your program showed the output for x because it is a primitive type & not a class. For a class you need a constructor & hence operator new or malloc aren't suitable for classes & hence the output. If you simply replace operator new with new & operator delete with delete then the output will be :-
constructing
5
1 2
executed
destroying
Now your code gives the correct & apt results ! Congo !
For your second question, NEVER MIX UP malloc & free with new & delete as it creates UB with not so happening results.

Related

C++ class destructor not being called automatically causes memory leak?

(Before anyone asks: no, i didn't forget the delete[] statement)
I was fiddling around with dinamically allocated memory and i run into this issue. I think the best way to explain it is to show you these two pieces of code I wrote. They are very similar, but in one of them my class destructor doesn't get called.
// memleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
void init() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
}
Leak() = default;
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
// I tried explicitly calling the destructor as well,
// but this somehow causes the same memory to be deleted twice
// and segfaults
// leak.~Leak();
leak = Leak();
leak.init();
}
}
// noleak.cpp
#include <vector>
using namespace std;
class Leak {
vector<int*> list;
public:
Leak() {
for (int i = 0; i < 10; i++) {
list.push_back(new int[2] {i, i});
}
};
~Leak() {
for (auto &i : list) {
delete[] i;
}
}
};
int main() {
Leak leak;
while (true) {
leak = Leak();
}
}
I compiled them both with g++ filename.cpp --std=c++14 && ./a.out and used top to check memory usage.
As you can see, the only difference is that, in memleak.cpp, the class constructor doesn't do anything and there is an init() function that does its job. However, if you try this out, you will see that this somehow interferes with the destructor being called and causes a memory leak.
Am i missing something obvious? Thanks in advance.
Also, before anyone suggests not using dinamically allocated memory: I knwow that it isn't always a good practice and so on, but the main thing I'm interested in right now is understanding why my code doesn't work as expected.
This is constructing a temporary object and then assigning it. Since you didn't write an assignment operator, you get a default one. The default one just copies the vector list.
In the first code you have:
Create a temporary Leak object. It has no pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes 0 pointers since its vector is empty.
Allocate a bunch of memory and store the pointers in the vector.
Repeat.
In the second code you have:
Create a temporary Leak object. Allocate some memory and store the pointers in its vector.
Assign the temporary object to the leak object. This copies the vector (overwriting the old one)
Delete the temporary object, this deletes the 10 pointers in the temporary object's vector.
Repeat.
Note that after leak = Leak(); the same pointers that were in the temporary object's vector are also in leak's vector. Even if they were deleted.
To fix this, you should write an operator = for your class. The rule of 3 is a way to remember that if you have a destructor, you usually need to also write a copy constructor and copy assignment operator. (Since C++11 you can optionally also write a move constructor and move assignment operator, making it the rule of 5)
Your assignment operator would delete the pointers in the vector, clear the vector, allocate new memory to hold the int values from the object being assigned, put those pointers in the vector, and copy the int values. So that the old pointers are cleaned up, and the object being assigned to becomes a copy of the object being assigned from, without sharing the same pointers.
Your class doesn't respect the rule of 3/5/0. The default-generated move-assignment copy-assignment operator in leak = Leak(); makes leak reference the contents of the temporary Leak object, which it deletes promptly at the end of its lifetime, leaving leak with dangling pointers which it will later try to delete again.
Note: this could have gone unnoticed if your implementation of std::vector systematically emptied the original vector upon moving, but that is not guaranteed.
Note 2: the striked out parts above I wrote without realizing that, as StoryTeller pointed out to me, your class does not generate a move-assignment operator because it has a user-declared destructor. A copy-assignment operator is generated and used instead.
Use smart pointers and containers to model your classes (std::vector<std::array<int, 2>>, std::vector<std::vector<int>> or std::vector<std::unique_ptr<int[]>>). Do not use new, delete and raw owning pointers. In the exceedingly rare case where you may need them, be sure to encapsulate them tightly and to carefully apply the aforementioned rule of 3/5/0 (including exception handling).

Double free or corruption after queue::push

#include <queue>
using namespace std;
class Test{
int *myArray;
public:
Test(){
myArray = new int[10];
}
~Test(){
delete[] myArray;
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
After I run this, I get a runtime error "double free or corruption". If I get rid of the destructor content (the delete) it works fine. What's wrong?
Let's talk about copying objects in C++.
Test t;, calls the default constructor, which allocates a new array of integers. This is fine, and your expected behavior.
Trouble comes when you push t into your queue using q.push(t). If you're familiar with Java, C#, or almost any other object-oriented language, you might expect the object you created earler to be added to the queue, but C++ doesn't work that way.
When we take a look at std::queue::push method, we see that the element that gets added to the queue is "initialized to a copy of x." It's actually a brand new object that uses the copy constructor to duplicate every member of your original Test object to make a new Test.
Your C++ compiler generates a copy constructor for you by default! That's pretty handy, but causes problems with pointer members. In your example, remember that int *myArray is just a memory address; when the value of myArray is copied from the old object to the new one, you'll now have two objects pointing to the same array in memory. This isn't intrinsically bad, but the destructor will then try to delete the same array twice, hence the "double free or corruption" runtime error.
How do I fix it?
The first step is to implement a copy constructor, which can safely copy the data from one object to another. For simplicity, it could look something like this:
Test(const Test& other){
myArray = new int[10];
memcpy( myArray, other.myArray, 10 );
}
Now when you're copying Test objects, a new array will be allocated for the new object, and the values of the array will be copied as well.
We're not completely out trouble yet, though. There's another method that the compiler generates for you that could lead to similar problems - assignment. The difference is that with assignment, we already have an existing object whose memory needs to be managed appropriately. Here's a basic assignment operator implementation:
Test& operator= (const Test& other){
if (this != &other) {
memcpy( myArray, other.myArray, 10 );
}
return *this;
}
The important part here is that we're copying the data from the other array into this object's array, keeping each object's memory separate. We also have a check for self-assignment; otherwise, we'd be copying from ourselves to ourselves, which may throw an error (not sure what it's supposed to do). If we were deleting and allocating more memory, the self-assignment check prevents us from deleting memory from which we need to copy.
The problem is that your class contains a managed RAW pointer but does not implement the rule of three (five in C++11). As a result you are getting (expectedly) a double delete because of copying.
If you are learning you should learn how to implement the rule of three (five). But that is not the correct solution to this problem. You should be using standard container objects rather than try to manage your own internal container. The exact container will depend on what you are trying to do but std::vector is a good default (and you can change afterwords if it is not opimal).
#include <queue>
#include <vector>
class Test{
std::vector<int> myArray;
public:
Test(): myArray(10){
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
The reason you should use a standard container is the separation of concerns. Your class should be concerned with either business logic or resource management (not both). Assuming Test is some class you are using to maintain some state about your program then it is business logic and it should not be doing resource management. If on the other hand Test is supposed to manage an array then you probably need to learn more about what is available inside the standard library.
You are getting double free or corruption because first destructor is for object q in this case the memory allocated by new will be free.Next time when detructor will be called for object t at that time the memory is already free (done for q) hence when in destructor delete[] myArray; will execute it will throw double free or corruption.
The reason is that both object sharing the same memory so define \copy, assignment, and equal operator as mentioned in above answer.
You need to define a copy constructor, assignment, operator.
class Test {
Test(const Test &that); //Copy constructor
Test& operator= (const Test &rhs); //assignment operator
}
Your copy that is pushed on the queue is pointing to the same memory your original is. When the first is destructed, it deletes the memory. The second destructs and tries to delete the same memory.
You can also try to check null before delete such that
if(myArray) { delete[] myArray; myArray = NULL; }
or you can define all delete operations ina safe manner like this:
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) { delete (p); (p) = NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p) = NULL; } }
#endif
and then use
SAFE_DELETE_ARRAY(myArray);
Um, shouldn't the destructor be calling delete, rather than delete[]?

Memory management differences in return by value

I'm trying to follow a tutorial here: regarding overloading operators, and I've found something that's really confused me.
There was a previous question on this very website here where this tutorial was discussed, namely regarding how the variables in the class were preserved because the whole class was passed back by value.
Whilst experimenting with the class definition I toyed with making the integer variables pointers (perhaps not sensible - but just to experiment!) as follows:
class CVector {
int* x;
int* y;
public:
CVector () {};
CVector (int,int);
CVector operator + (CVector);
~CVector ();
};
In the class constructor I allocate memory for the two integers, and in the class deconstructor I delete the allocated memory.
I also tweak the overloaded operator function as follows:
CVector CVector::operator+ (CVector param) {
CVector temp;
*temp.x = *x + *param.x;
*temp.y = *y + *param.y;
return (temp);
}
For the original code, where the class has simple integer variables the return by value of the entire class completes successfully.
However, after I change the variables to int pointers, the return by value of the class does not complete successfully as the integer variables are no longer intact.
I assume the deconstructor is being called when the temporary CVector goes out of scope and deletes these member integer pointers, but the class itself is still returned by value.
I'd like to be able to return by value the CVector with the memory allocated to its member variables intact, whilst ensuring the temporary CVector is correctly deleted when it goes out of scope.
Is there any way this can be done?
Many thanks!
The problem is that you are not following the rule of the three, which basically boils down to: *if you manage resources, then you should provide copy constructor, assignment operator and destructor for your class*.
Assuming that on construction you are allocating memory for the pointers, the problem is that the implicit copy constructor is shallow, and will copy the pointers, but you probably want a deep copy. In the few cases where you do not want a deep copy, control of the manage shared resource becomes more complicated, and I would use a shared_ptr rather than trying to do it manually.
You need to provide a copy constructor for CVector to make copies of the allocated memory. Otherwise, when you return by value, the pointer values will simply be copied and then the temp object is destructed, deallocating the ints. The returned copy now points to invalid memory.
CVector( const CVector& other )
: x ( new int(other.x) )
, y ( new int(other.y) )
{}
Note that it is bad idea to be using raw pointers in your class, especially more than one. If the allocation of y fails above and new throws you've got a memory leak (because x is left dangling). You could've allocated within the constructor itself, instead of the initializer list, either within a try-catch, or using the std::nothrow version of new, then check for nullptr. But it makes the code very verbose and error prone.
The best solution is to use some smart pointer class such as std::unique_ptr to hold pointers. If you were to use std::shared_ptr to hold those pointers, you can even share the ints between copies of the class.
The return-by-value causes the returned, temp object to be copied to another object, a temporary "return object". After temp is copied, it is destructed, deallocating your ints. The easiest way to handle this is to use a reference-counted pointer such as tr1::shared_ptr<>. It will keep the memory allocated until the last reference to it is dropped, then it will deallocate.
There are few problems in the given code.
(1) You should allocate proper memory to *x and *y inside the constructor; otherwise accessing them is undefined behavior.
CVector () : x(new int), y(new int) {}
Also make sure that to have copy constructor and operator = where you delete x and delete y before reallocating them; otherwise it will lead to hazards.
(2) delete them in destructor
~CVector () { delete x; delete y; }
(3) Pass argument to operator + by const reference to avoid unnecessary copying.
CVector CVector::operator+ (const CVector &param)
{
// code
}
Since you are learning with playing around with pointers, I will not comment on the design perspective of your class, like if they should be pointer or variables or containers and so on.

explicit destructor

The following code is just used to illustrate my question.
template<class T>
class array<T>
{
public:
// constructor
array(cap = 10):capacity(cap)
{element = new T [capacity]; size =0;}
// destructor
~array(){delete [] element;}
void erase(int i);
private:
T *element;
int capacity;
int size;
};
template<class T>
void class array<T>::erase(int i){
// copy
// destruct object
element[i].~T(); ////
// other codes
}
If I have array<string> arr in main.cpp. When I use erase(5), the object of element[5] is destroyed but the space of element[5] will not be deallocated, can I just use element[5] = "abc" to put a new value here? or should I have to use placement new to put new value in the space of element [5]?
When program ends, the arr<string> will call its own destructor which also calls delete [] element. So the destructor of string will run to destroy the object first and then free the space. But since I have explicitly destruct the element[5], does that matter the destructor (which is called by the arr's destuctor) run twice to destruct element[5]? I know the space can not be deallocated twice, how about the object? I made some tests and found it seems fine if I just destruct object twice instead of deallocating space twice.
Update
The answers areļ¼š
(1)I have to use placement new if I explicitly call destructor.
(2) repeatedly destructing object is defined as undefined behavior which may be accepted in most systems but should try to avoid this practice.
You need to use the placement-new syntax:
new (element + 5) string("abc");
It would be incorrect to say element[5] = "abc"; this would invoke operator= on element[5], which is not a valid object, yielding undefined behavior.
When program ends, the arr<string> will call its own destructor which also calls delete [] element.
This is wrong: you are going to end up calling the destructor for objects whose destructors have already been called (e.g., elements[5] in the aforementioned example). This also yields undefined behavior.
Consider using the std::allocator and its interface. It allows you easily to separate allocation from construction. It is used by the C++ Standard Library containers.
Just to explain further exactly how the UD is likely to bite you....
If you erase() an element - explicitly invoking the destructor - that destructor may do things like decrement reference counters + cleanup, delete pointers etc.. When your array<> destructor then does a delete[] element, that will invoke the destructors on each element in turn, and for erased elements those destructors are likely to repeat their reference count maintenance, pointer deletion etc., but this time the initial state isn't as they expect and their actions are likely to crash the program.
For that reason, as Ben says in his comment on James' answer, you absolutely must have replaced an erased element - using placement new - before the array's destructor is invoked, so the destructor will have some legitimate state from which to destruct.
The simplest type of T that illustrates this problem is:
struct T
{
T() : p_(new int) { }
~T() { delete p_; }
int* p_;
};
Here, the p_ value set by new would be deleted during an erase(), and if unchanged when ~array() runs. To fix this, p_ must be changed to something for which delete is valid before ~array() - either by somehow clearing it to 0 or to another pointer returned by new. The most sensible way to do that is by the placement new, which will construct a new object, obtaining a new and valid value for p_, overwriting the old and useless memory content.
That said, you might think you could construct types for which repeated destructor was safe: for example, by setting p_ to 0 after the delete. That would probably work on most systems, but I'm pretty sure there's something in the Standard saying to invoke the destructor twice is UD regardless.

c++ must delete a references?

in the following code:
class x
{
private:
someRef& m_ref;
public:
x(someRef& someRef):m_ref(someRef)
{
}
do I need to do:
~x()
{
delete m_ref;
}
which by the way doesnt work without getting the pointer...
basically I'm asking: Do I need to call a destructor on a reference member?
No.
You only need to delete an object if you own it. If you were passed a reference, it means that someone else owns it, thus it's unnecessary and thankfully the language prevents it.
I don't think one actually strictly speaking ever deletes even pointers. What you delete are dynamically allocated objects (or arrays of objects) that the pointer is a handle for. If the object originates from a call to new and it is the responsibility of this class to clean up after this object, then you call delete.
It is technically possible that a reference might be referring to a dynamically allocated object:
int main()
{
//in principle a reference can also refer to a dynamically allocated object
x var(*new someRef);
}
//and if that is the intended usage:
x::~x()
{
delete &m_ref;
}
However, this would be incredibly bad style. By convention, the "owning" handle of a dynamically allocated object should not be a reference.
No. You can only delete pointers, not references, and even then you must only delete objects that you allocated using the new operator. And then you must be sure to delete them only once. Here is the case in which you would need to use delete in your destructor:
class x
{
private:
someObj* m_ptr;
public:
x():m_ptr(new someObj())
{
}
~x()
{
delete m_ptr;
}
But in general it's best to avoid even this and use smart pointers instead.
I want to clarify some misconceptions you seem to have that are beyond the intent of your question:
When a class's destructor is called all of it's members' destructors get called as well.
Calling delete is not the same as calling the destructor. delete explicitly calls the destructor and also calls operator delete at the objects location, it is a 2 part thing.
For a small bit of extra clarification I want to offer the following:
int *pi = new int;
//int& ir = pi; // can't do
// this a reference to the pointer but it is an error
// because or the type difference int& vs int* and
// static_cast won't help. reinterpret_cast would allow
// the assignment to take place but not help the 'delete ir'
int& ir = *pi; // this is OK - a reference to what the pointer points to.
// In other words, the the address of the int on the heap.
//delete ir; // can't do, it is a reference and you can't delete non-pointers.
delete &ir; // this works but it is still not "deleting a reference".
// The reference 'ir' is another name for the heap-based int.
// So, &ir is the address of that int, essentially a pointer.
// It is a pointer that is being used by delete, not a reference.