Here is an example of a class that is made available for the + operation.
class A
{
public:
int *array;
A()
{
array = new int[10];
}
~A()
{
delete[] array;
}
A operator+ (const A &b)
{
A c;
for(int i=0; i<10; i++)
c.array[i] += array[i] + b.array[i];
return c;
}
};
int main()
{
A a,b,c,d;
/* puts some random numbers into the arrays of b,c and d */
a = b+c+d;
}
Will a run the destructor before copying the result of b+c+d or not? If not, how do I make sure no memory is leaked?
The + operator overload is designed this way such that no operand is modified.
You need to add an equals operator to A. Also, you will likely want to create a copy constructor.
When a becomes the return from b+c+d, the array pointer in a gets over written without delete[] ever being called on it. You need to make an operator= that deletes the array.
An example of an operator= is below:
A& operator=(A const& a)
{
if (&a != this) {
int* tmp = this->array;
this->array = new int[10];
//copy a.array to this->array
delete[] tmp;
}
return *this;
}
There's a lot of subtleties in this if you're new to operator=.
In particular, the check whether or not a is equal to this is necessary because it's perfectly valid to write:
A a;
a = a;
This would cause a pointless copy, and in most cases of operator= will cause bugs.
The other subtlety is less of a requirement than that one and more of a coding style (though a very wide spread standard). When copying something that is dynamically allocated, you always want to allocate and copy before you release. That way, if new throws an exception (or something else fails), the object is still in a stable state, though with it's old data instead of the new expected dated.
Will this cause memory leak?
Yes, it will. You forgot to add copy constructor and assignment operator. See Rule of Three
You could also use std::vector<int> for A::array instead of int*. In this case you wouldn't need to worry about copy constructor/assignment operator (as long as you don't add something else that must be handled in destrcutor).
Related
So, for instance, I have the following code which I want a object's pointer
member to point to a memory which was pointed by another temporary object's
member.
struct A {
int * vals;
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 100;
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
I set temp.vals to nullptr in case the destructor of temp will free that
memory. So far so good, I guess. However, if I change the vals to a dynamic
array, i.e. a pointer to pointers:
struct A {
int ** vals;
A(): vals(new int*[10]) {
for (int i = 0; i < 10; ++i) {
vals[i] = new int;
}
}
~A(){
for (int i = 0; i < 10; ++i) {
delete vals[i]; // illegal to dereference nullptr
}
delete [] vals;
}
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = new int(1);
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
}
I have add a for loop in destructor to handle the nested allocated memory, and
to avoid the memory be freed by the destructor of temp, I set temp.vals to
nullptr, which, however will cause a segmentation fault since when destructor
of temp is called, it is illegal to dereference a nullptr.
So my question is, how to correct set the destructor to handle the dynamic array.
I'm not a native speaker, so please forgive my grammar mistakes.
The typical C++ solution looks a bit different:
class A {
private:
int* vals;
public:
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
A (A const& src); // Copy constructor
A (A&& src) : vals (src.vals) { src.vals = nullptr; }
A& operator=(A const&); // Assignment
A& operator=(A &&);
};
You can now write a = std::move(temp). Outside the class, you don't need to know how the inside works.
For your 2D array, just define the same special member functions. This is usually called the "Rule of Five". If you need a destructor, you probably need the other 4 functions as well. The alternative is the "Rule of Zero". Use std::vector or another class that manages memory for you.
However, if I change the vals to a dynamic array, i.e. a pointer to pointers
In the first program, vals is a pointer. It points to a dynamic array of integers. In the second program, vals is also a pointer. It points to a dynamic array of pointers.
how to correct set the destructor to handle the dynamic array.
You set vals to null. If null is a valid state for vals, then it isn't correct to unconditionally indirect through it in the destructor. You can use a conditional statement to do so only when vals isn't null.
However, the program is hardly safe because vals is public, and thus it is easy to mistakenly write a program where it is assigned to point to memory that isn't owned by the object. In cases where destructor cleans up an owned resource, it is important to encapsulate the resource using private access to prevent accidental violation of class invariants that are necessary to correctly handle the resource.
Now that vals is no longer outside of member functions, you cannot transfer the ownership like you did in your example. The correct way to transfer the ownership is to use move assignment (or constructor). The implicitly generated move constructor cannot handle an owning bare pointer correctly. You must implement them, as well as the copy assignment and constructor.
Furthermore, you should use an owning bare pointer in the first place. You should use a smart pointer instead. If you simply replaced the bare pointers with unique pointer, then the implicitly generated move assignment and constructor would handle the resource correctly, and the copy assignment and constructor would be implicitly deleted.
Lastly, the standard library has a container for dynamic arrays. Its called std::vector. There's typically no need to attempt to re-implement it. So in conclusion, I recommend following:
std::vector<int> a;
{
std::vector<int> temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 1;
}
a = std::move(temp);
}
There are still issues such as the temporary variable being entirely unnecessary, and the loop could be replaced with a standard algorithm, but I tried to keep it close to the original for the sake of comparison.
P.S. It's pretty much never useful to dynamically allocate individual integers.
So let's say we have a simple variable-length array class like following:
struct VLA {
double* d=nullptr;
int dim;
}
What makes me wonder is, within operator=, should I check (and perhaps free/delete if not nullptr) d before malloc/new an new array for it? As assignment is different from copy constructor where it might originally also carried an array.
Like following example:
operator=(VLA &other) {
double *tmp=new double[dim];
memcpy(tmp, other.d, sizeof(double)*other.dim);
delete[]d;
d=tmp;
dim=other.dim;
}
Is the delete[]d required?
within operator=, should I check (and perhaps free/delete if not nullptr) d before malloc/new an new array for it?
Is the delete[]d required?
If you are going to allocate a new array with new[], then yes, you need to free the the old array with delete[], otherwise it will be leaked. Whether you do that before or after allocating the new array is up to you, but I would do it after, in case allocating the new array fails.
Note that you can optimize the code you have shown a little, by skipping the new[]/delete[] if the new dim is the same value as the old dim, and by using the copy-swap idiom when you do allocate a new array:
VLA(const VLA &other) {
d = new double[other.dim];
memcpy(d, other.d, sizeof(double) * other.dim);
dim = other.dim;
}
VLA& operator=(const VLA &other) {
if (this != &other) {
if (dim == other.dim) {
memcpy(d, other.d, sizeof(double) * other.dim);
else {
VLA temp(other);
std::swap(d, temp.d);
std::swap(dim, temp.dim);
}
}
return *this;
}
Though, you really should should be using std::vector instead of new[]/delete[] manually at all. Let std::vector handle the array for you:
#include <vector>
struct VLA {
std::vector<double> d;
int dim() const { return d.size(); }
// compiler-generated copy constructor will "do the right thing"...
// compiler-generated operator=() will "do the right thing"...
};
I create a class type Test and constructor with parameter, however, when I want to assign the constructor I create to a new constructor through the function f, the program crashes! Did anybody know why!?
The code:
class Test
{
public:
int number;
int *a;
Test(int n){
a = new int[n];
}
~Test(){
delete []a;
}
};
Test f(Test Ft1)
{
// Do something.
return Ft1;
}
int main()
{
Test t1(3);
t1.number = 5;
Test t2 = f(t1);
return 0;
}
The problem is that you are deleting twice the same array a when t1 and t2 destructors are called:
t1 and t2 have their member variable a pointing to the same memory location. When you do Test t2 = f(t1), a copy of t1 is created and is assigned to t2. You did not define a specific copy constructor, so the compiler defined it implicitly for you. However it simply copies the value of a (and does not do a new allocation as you might expect).
As best practice, I would recommend to add your own:
- copy constructor
- copy assignment
(cf rule of three)
Concerning the variable member a design:
- If you want t1 and t2 to point to the same array, then you can use shared_ptr
- If you want t1 and t2 to have their own array, then it would be simpler to use a vector<int> for a
Edit: in case you need to use a raw pointer, here is a quick example of how you can manage the memory in copy constructor and operator assignment. May I recommend you to read a reference book about it (for instance Effective C++ , chapter 11)? It will explain you the key concepts and the pitfalls.
class Test{
public:
int number;
int *a;
Test(int n){
a = new int[n];
}
~Test(){
delete [] a;
}
Test(const Test& that)
{
int size = sizeof(that.a);
a = new int[size];
memcpy (a, that.a, sizeof(size));
}
Test& operator=(const Test& that)
{
if (this != &that)
{
delete [] a;
int size = sizeof(that.a);
a = new int[size];
memcpy (a, that.a, sizeof(size));
}
return *this;
}
};
Test f(Test Ft1){
//do something
return Ft1;
}
int main(){
Test t1(3);
t1.number = 5;
Test t2 = f(t1);
// Test t3(t1); // calls copy constructor
// t3 = t1; // calls assignment operator
return 0;
}
The cause of your problem is that there is a thing called "binary copy". When special assignment/copy constructors are not defined, this binary copy kicks in. When one of your object gets copied over another, 2 different instances start own the same array because the pointer gets overwritten and the original array from the destination object gets leaked.
Compiler thinks that it is ok to copy contents of one object to another with a simple memcpy() (the picture is slightly more simplified but in essence what I write is correct). This is a constant source of problems, but this is how the language is defined. There is no way to do it any other way today. Tons of code are written and these tons expect exactly this.
First you need to decide what should happen with this array after copying. Should both objects co-own the array of the source object, should this array be duplicated at this point or anything else. Once you decide this, you need to implement this strategy in the assignment/copy constructors.
I have recently had some errors (bad_alloc) due to my lack of a destructor.
I currently have two classes, set up in this way:
class ObjOne {
friend class ObjTwo;
public: //constructors and some other random methods
ObjOne(int n) {
}
ObjOne() {
}
private:
int currSize;
int size;
int *jon;
};
class ObjTwo {
public: //constructors and some other methods
ObjTwo(ObjOne, int n) {} //
ObjTwo() {}
ObjTwo(const ObjTwo &source) { //copy constructor
num = source.num;
x = source.x;
myObjOne=source.myObjOne;
}
~ObjTwo() { //destructor
delete #
delete &x;
delete &myObjOne;
}
private:
ObjOne myObjOne;
int num, x;
};
and here is my operator= for ObjTwo
ObjTwo& ObjTwo::operator=(const ObjTwo& other) {
num = source.num;
x = source.x;
myObjOne=source.myObjOne;
return *this;
}
Firstly, my assumptions were (Please correct these if it is incorrect):
ObjOne does NOT need a destructor, as it is only primitive types, and when the compiler will use the default destructor to clean it up.
ObjTwo DOES need a destructor, as it contains ObjOne
ObjTwo Destructor will need to deallocate memory from x,num and myObjOne.
I have made a few attempts at destructors with this, however I still run into bad_alloc errors (when testing with huge loops etc.) or other errors (with the current one it just crashes when destructor is called).
Any guidance on what I am doing wrong is appreciated
EDIT:
I have a bad_alloc exception being thrown when I simply put this in a loop:
ObjTwo b(//some parameters);
ObjTwo a(//some parameters);
for (int i=0; i<20000000; i+) {
bool x = (a == b);
}
and this is overloaded == operator
bool ObjTwo::operator==(const ObjTwo& other) {
ObjTwo temp = other;
for(int i=myObjOne.x; i>=0; i--) {
if(myObjOne.get(i)!=temp.myObjOne.get(i)) {
return false;
}
}
return true;
}
After some reading on the error it seemed that it was caused to due running out of memory; which my unfunctioning destructor would cause. What could be the problem here?
and the get method simply returns jon[i];
You do not need any of your uses of delete. You should only delete something that you have previously allocated with new.
In ObjTwo, the members myObjOne, num, and x definitely should not be deleted. In fact, you should never take the address of a member and delete it. Members are destroyed automatically when the object they are a member of is destroyed.
Consider, for example, having a member which was defined like this:
int* p;
This p is a pointer to int. The pointer itself will be destroyed when the object it is part of is destroyed. However, imagine that in the constructor you dynamically allocate an int object like so:
p = new int();
Now, because new dynamically allocate objects, you will need to delete the object pointed to by p. You should do this in the destructor with delete p;. Note that this isn't destroying p, it's destroying the object it points out. Since p is a member, you should not destroy it manually.
ObjOne MIGHT need a destructor. This is not about primitive types, but about things like dynamically allocated memory (pointers). You have an int* member, which might be allocated dynamically or at least be a pointer to dynamic memory. So you will need to use delete or delete[] on this one.
What you are doing in ~ObjectTwo is fatal! You are trying to delete memory from the stack -> undefined behavior but will mostly crash. All of your objects/variables are stack-allocated, so you must not delete them...
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class myClass{
public:
int *num1;
myClass();
};
myClass::myClass(){
num1 = new int[1];
num1[0] = 10;
}
int main()
{
myClass *myclass;
myclass = new myClass[10];
cout << myclass[0].num1[0] << endl;
delete &myclass[0];
cout << myclass[0].num1[0] << endl;
}
I want to delete the first instance of myclass (myclass[0]).
This code does not run correctly, it fails during the delete part. There is probably something I am missing.
What did I do wrong?
You cannot delete just a portion of an array created with new. new allocates a block of memory which can only be deleteed all together.
If you want an object to free its own internal data you'll have to arrange for the class, which should encapsulate and hide its own internal resources, to do that itself.
If you want a smaller block of memory holding the array you allocated, then you must allocate a smaller block and move the contents that you wish to keep into the new block, and then delete the entire old block:
int *arr = new int[10];
int *tmp = new int[9];
std::copy(arr+1, arr+10, tmp);
delete [] arr;
arr = tmp;
You need to design your class to manage its own resources, and to handle copying or moving. Your current myClass allocates an array but relies on other code to handle cleaning up. This is not a good way to go about doing this, because often no other code is in a good position to do the correct thing, and even when you could you'll very frequently make mistakes.
Since you're allocating in the constructor you need a destructor that handles deallocation. And then since you implement one of three special operations (copy-ctor, copy-assignment, destructor) you need to consider implementing them all. (This is called 'The Rule of Three'. In C++11 it becomes 'The Rule of Five' with the addition of move-ctors and move assignment.)
class myClass {
public:
myClass();
// destructor to handle destroying internal resources correctly
~myClass();
// copy constructor and copy assignment operator, to handle copying correctly
myClass(myClass const &rhs);
myClass &operator=(myClass const &rhs);
// move constructor and move assignment operator, to handle moves correctly (C++11)
myClass(myClass && rhs);
myClass &operator= (myClass &&rhs);
private:
int *num1; // private so external code can't screw it up
public:
// limited access to num1
int size() const { if (num1) return 1; else return 0; }
int &operator[] (size_t i) { return num1[i]; }
};
You can implement the constructor just as you did, or you could use the initializer list and C++11 uniform initialization:
myClass::myClass() : num1(new int[1]{10}) {}
Now, the destructor you want depends on the semantics you want the class to have, and the particular invariants you want to maintain. 'value' semantics are the norm in C++ (if you're familiar with Java or C# those languages encourage or require 'reference' semantics for user defined types). Here's a destructor you might use if you want value semantics, and if you maintain an invariant that num1 always owns memory or is null.
myClass::~myClass() { delete num1; }
Copying and moving can be handled in different ways. If you want to disallow them entirely you can say (in C++11):
myClass::myClass(myClass const &rhs) = delete;
myClass &myClass::operator=(myClass const &rhs) = delete;
myClass::myClass(myClass && rhs) = delete;
myClass &myClass::operator= (myClass &&rhs) = delete;
Or if you want to allow copying and or moving (and maintain value semantics and the invariant mentioned above) then you can implement either or both of these pairs of functions:
myClass::myClass(myClass const &rhs) : num1( rhs.size() ? new int[1]{rhs[0]} : nullptr) {}
myClass &myClass::operator=(myClass const &rhs) {
if (num1)
num1[0] = rhs[0];
}
myClass::myClass(myClass && rhs) : num1(rhs.num1) { rhs.num1 = nullptr; } // remember to maintain the invariant that num1 owns the thing it points at, and since raw pointers don't handle shared ownership only one thing can own the int, and therefore only one myClass may point at it. rhs.num1 must be made to point at something else...
myClass &myClass::operator= (myClass &&rhs) { std::swap(num1, rhs.num1); } // steal rhs.num1 and leave it to rhs to destroy our own num1 if necessary. We could also destroy it ourselves if we wanted to.
With this implementation you can now treat a myClass object the same as you would an int or any other 'value' type. You no longer need to worry about managing its internal resources; it will take care of them itself.
int main() {
std::vector<myClass> myclassvec(10);
cout << myclassvec[0][0] << '\n';
myclassvec.erase(myclassvec.begin()); // erase the first element
cout << myclassvec[0][0] << '\n'; // access the new first element (previously the second element);
}
Create a function inside of your class the handles the deletion of its private members, maybe called FreeMem(int index)
void myClass::FreeMem()
{
delete [] num1
}
But honestly, freeing memory of an object without the use of a destructor in this sort of a program is hazardous and downright bad practice. I would recommend freeing the memory in your destructor, so when the object terminates it frees the memory,
myClass::~myClass()
{
delete [] num1;
}
Another thing to note on, if you're only creating one value in your dynamic variable, it would be easier to write it as:
int * pnum = new int;
//or in your class..
pnum = new int;
among other things, you have a lot of flaws in your program. I would recommend re-reading up on classes again.