I wrote the following dummy class to understand how the copy constructor,the copy assignment operator and the destructor works:
#include <string>
#include <iostream>
class Box {
public:
// default constructor
Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { a=other.a; s=new std::string(*other.s); }
// copy assignment operator
Box &operator=(const Box &other) { a=other.a; s=new std::string(*other.s); }
// destructor
~Box() { std::cout<<"running destructor num. "<<++counter<<std::endl; }
int get_int() { return a; }
std::string &get_string() { return *s; }
private:
int a;
std::string *s;
static int counter;
};
int Box::counter=0;
I'm using this class type in my code to test how it works but I was thinking about the implications in destroying objects which have a member of built-in pointer type:
#include "Box.h"
using namespace std;
int main()
{
Box b1;
Box b2(2,"hello");
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
cout<<b2.get_int()<<" "<<b2.get_string()<<endl;
Box b3=b1;
Box b4(b2);
cout<<b3.get_int()<<" "<<b3.get_string()<<endl;
cout<<b4.get_int()<<" "<<b4.get_string()<<endl;
b1=b4;
cout<<endl;
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
{
Box b5;
} // exit local scope,b5 is destroyed but string on the heap
// pointed to by b5.s is not freed (memory leak)
cout<<"exiting program"<<endl;
}
This pointer is initialized in the constructor to point to a (always new) dynamically allocated memory on the free store. So,when the destructor is called, members of the object to be destroyed are destroyed in reverse order. Is it right in this case, that only the int and the pointer objects are destroyed, and I end up having a memory leak (the string on the heap is not freed)?
Moreover, defining this copy assignment operator, do I have a memory leak every time I assign an object (the pointer points to a new object on the heap and the former is lost isn't it?) ?
Each time you call new, you have to delete it (except are shared pointers).
So you have to delete the string in the destructor.
The assignment operator works on an existing instance, so you already created s and do not have to create a new string for s.
the destructor destructs its members. Since a pointer is like a int, only the variable holding the address is destructed, not the object it is pointing to.
So yeah, you will have a memory leak in each object and everytime you use the assignment operator the way you designed your class.
Keep in mind allocation happens on base construction, copy construction and surprisingly conditionally on assignment
Deallocation happens in the destructor and conditionally on assignment
The condition to watch for is:
x = x;
So your code can be changed to the following pattern (in cases where you are not able to use the preferred appropriate smart pointer)
Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { cp(other); }
// copy assignment operator
Box &operator=(const Box &other) {
if (&other != this) // guard against self assignment
{
rm();
cp(other);
}
return *this;
}
// destructor
~Box() { rm(); }
private:
void cp(const Box &other) {a=other.a; s=new std::string(*other.s);
void rm() {
std::cout<<"running destructor num. "<<++counter<<std::endl;
delete s; // prevents leaks
}
One possible way to deal with unnamed dynamically allocated members is to save them in a container every time they are created (in an object, function, etc), and then to run a for loop in your destructor with a delete statement followed by the elements of the container.
You can do this with a vector:
vector <string*> container;
and you can use it as follows:
// define it in the private members of your class
vector <string*> container;
// use it when you create the string
container.push_back(new dynamicallyAllocatedObject);
// free memory in the destructor
for(auto it = container.begin(); it != container.end(); ++it) delete *it;
Related
Slowly learning about copy/move constructors, rule of 5 etc. Mixed with not-so-well understanding of usage of pointers/reference, I cannot understand why my destructor throws the error below. I know that it's caused by destructor and destructor only, and after the copy constructor.
untitled(19615,0x104a60580) malloc: *** error for object 0x600000b74000: pointer being freed was not allocated
untitled(19615,0x104a60580) malloc: *** set a breakpoint in malloc_error_break to debug
Code:
#include <string>
using namespace std;
typedef int size_type;
class user{
public:
user():
rank(1),
name("default"){
}
private:
int rank;
string name;
};
class account{
public:
account(size_type max_size):
owners(new user[max_size]),
max_size(max_size){
cout<<"normal constructor"<<endl;
}
account(account& other):
owners(other.owners),
max_size(sizeof(owners)){
cout<<"copy constructor called"<<endl;
}
account(account&& other):
owners(other.owners),
max_size(sizeof(owners)){
cout<<"move constructor called"<<endl;
}
~account(){
if(owners!= NULL) {
delete[] owners;
owners= 0;
}
cout<<"destructor called"<<endl;
}
private:
user* owners;
size_type max_size;
};
int main(){
account f(3);
account n(f);
}
I cannot understand why my destructor throws the error below. I know that it's caused by destructor and destructor only
account f(3);
The constructor of this object allocates an array.
account n(f);
The copy constructor that you wrote copies the pointer that points to the dynamic array.
n is destroyed first. Its destructor deletes the array. f is destroyed after that. Its destructor also deletes the same array and the behaviour of the program is undefined, which lead to the output that you observed.
To prevent the allocation from being deleted multiple times, you must enforce a class invariant (a post condition that applies to all member functions) that any non-null owners value must be unique across all instances of the class. To maintain that invariant in the copy constructor (as well as move constructor and copy and move assignment operators), you must not copy the pointer, as you do now. I recommend studying the RAII idiom.
Better solution: Don't use owning bare pointers. Use std::vector<user> and don't have user defined special member functions at all.
P.S. The copy constructor should accept a reference to const.
Also:
if(owners!= NULL) {
delete[] owners;
owners= 0;
}
The check is redundant because it's safe to delete null. The assignment is redundant because the object is about to be destroyed and the member cannot be accessed after that anyway.
I am pretty new to the C++ world...
I have a question about destructors in C++.
If there is a class like:
class TestClass {
public:
double *array;
}
When I put a pointer of one array to *array and put again another and delete Testclass instance, then I can no longer access the older one?
It becomes an error:
int main() {
TestClass tc;
tc.array = new double[10];
double *array2 = tc.array;
tc.array[3]=9;
tc.array = new double[10];
delete &tc; // <------------------- this one.
std::cout<<array2[3]<<std::endl;
// std::cout<<tc.array[3]<<array2[3]<<std::endl;
}
If there is no delete &tc and activate the commentline (the last line),
'09' shows up, (tc.array[3] != array2[3] => tc.array != array2)
which does not mean tc.arrray is not the one in *array2 ??
What is wrong?
The tc is a function-scoped variable (allocated on the stack). It's not allocated with new. You can't delete it. it will be freed automatically when the function return
Dealing with raw pointers is somewhat tricky and your class would probably benefit from using a std::vector<double> instead of a raw pointer. Another choice could be a std::unique_ptr<double[]> that handles deleting the pointer for you.
That said, if you want to try it out, you should know when and what to delete.
tc is an automatic variable. You didn't create tc using new so you should not delete it. It will be destroyed when it goes out of scope - when the program leaves the block in which tc was created.
You haven't defined a destructor for TestClass so the memory to which array points will still be allocated even after tc is destroyed. The destructor would typically look like this:
~TestClass() {
delete[] array;
}
You also assign directly to tcs internal pointer, which is dangerous. You should have just as many delete[] as you have new[]s, which is not the case in your program, so it'll leak. You should typically hide the internal pointer so it can't be reassigned without the object owning it having control.
For manual memory management to work properly, there are some member functions you should consider:
Copy constructor
Move constructor
Copy assignment operator
Move assignment operator
Destructor
You can read more about those here: The rule of three/five/zero
Here's an example of what your class could look like with the 5 member functions mentioned above plus a default constructor, a converting constructor taking a pointer as parameter and two subscript operators.
#include <iostream>
#include <utility> // std::move, std::swap, std::exchange
class TestClass {
public:
// default constructor
TestClass() :
array(nullptr) // member initializer
{
std::cout << "default ctor\n";
}
// converting constructor - refuse lvalue pointers since we want to make sure
// that we "own" the pointer
TestClass(double*&& p) : array(p) {
std::cout << "converting ctor " << p << "\n";
}
// copy constructing without knowledge about the size of the array isn't possible
TestClass(const TestClass&) = delete;
// move construction works though
TestClass(TestClass&& rhs) :
array(std::exchange(rhs.array, nullptr)) // steal pointer from rhs
{
std::cout << "move ctor\n";
}
// copy assignment without knowledge about the size of the array isn't possible
TestClass& operator=(const TestClass&) = delete;
// move assignment works though
TestClass& operator=(TestClass&& rhs) {
std::cout << "move assignment\n";
// swap pointers with rhs - let rhs delete[] our current pointer
std::swap(array, rhs.array);
return *this;
}
~TestClass() { // destructor
delete[] array;
}
// subscripting support
double& operator[](size_t idx) { return array[idx]; }
double operator[](size_t idx) const { return array[idx]; }
private: // hide your raw pointer from direct access
double* array;
};
void printer(const TestClass& tc, size_t idx) {
// use const version of operator[] in the class
std::cout << tc[idx] << "\n";
}
int main() {
TestClass tc; // default ctor
// use the converting constructor that creates a TestClass object from a pointer.
// It is then move assigned to tc
tc = new double[10];
tc[3] = 1; // use the non-const version of operator[] in the class
printer(tc, 3);
double* a = new double[10];
// tc = a; // this won't work since we don't accept lvalues in assignment
tc = std::move(a); // make an xvalue to allow the assignment. "a" should not be
// delete[]-ed after this since we granted tc the possibillity
// to take ownership the pointer.
tc[3] = 2;
printer(tc, 3);
}
I got the follwing block of code:
#include <vector>
#include <iostream>
struct TestStruct {
bool wasCreated;
TestStruct() {
std::cout << "Default Constructor" << std::endl;
wasCreated = false;
}
~TestStruct() {
if (wasCreated) {
DoImportantStuff();
}
}
void Create() {
wasCreated = true;
}
// delete all copy stuff
TestStruct(const TestStruct&) = delete;
TestStruct& operator=(const TestStruct&) = delete;
// implement only move assignment & ctor
TestStruct(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
}
TestStruct& operator=(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
return *this;
}
// very important stuff
void DoImportantStuff() {
std::cout << "Do Important Stuff" << std::endl;
}
};
int main() {
std::vector<TestStruct> testVector;
testVector.emplace_back(TestStruct());
testVector.emplace_back(TestStruct());
std::cin.get();
}
This code leads to the output:
Default Constructor
Do Important Stuff
Default Constructor
Do Important Stuff
Do Important Stuff
Basicly I wanted to write a class, which owns memory but allocates this memory only when I call Create(). To avoid memory leaks and to avoid deleting not allocated memory I introduced wasCreated which will be only true when i call Create(). Every TestStruct should be saved in one vector. So in implemented move assigment & ctor and deleted both copy assigment & ctor.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory. Why is so and how do get the vector to call the default constructor on memory allocation? Do I need my own allocator?
Your problem is that your move constructor is implemented incorrectly. It swaps wasCreated between the newly created object and the one being moved from, but the variable in the newly created object has not been initialized yet (a default-constructed bool has an unknown value). So your temporary objects created with TestStruct() receive an uninitialized bool, which happens to be true in your case, hence the calls to DoImportantStuff() in their destructors.
So the move constructor should look something like this:
// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
other.wasCreated = false;
}
(You have moved ownership to the newly created object, the old one doesn't own anything anymore.)
Don't confuse the assignment operator with the constructor; they do different things. The assignment operator deals with two objects that are both already constructed; in the case of the constructor, the object being constructed is, well..., not constructed yet, so it doesn't have a valid state.
By the way, emplace_back() is pointless the way you're using it. Its purpose is to forward its arguments directly to the constructor of the object inside the vector. Since you have a default constructor (no arguments), the call should be:
testVector.emplace_back();
This will default-construct the TestStruct in place.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory.
A default-constructed vector has zero size, so there are no objects to construct.
If you want the vector to default-construct some objects, resize it.
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.