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.
Related
i had one of these q asked in my test (the output). i searched a lot but unable to understand why
#include <iostream>
using namespace std;
class building{
public:
building() {
cout<<"geek building"<<endl;
}
};
class house: public building{
public:
house(){
cout<<"geek house"<<endl;
}
house(string name){
new (this) house();
cout<<"geek house: string constructor"<<endl;
}
};
int main()
{
house h("geek");
return 0;
}
i am having problem with the following
new (this) house;
From n3337, chapter 3.8 (Object lifetime):
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undeļ¬ned behavior.
my code is giving the following output:
geek building
geek building
geek house
geek house: string constructor
i have following two Questions:
1)is it even legal to use this pointer with placement new inside a constructor of a live object. i know that there wouldn't be a problem if we used another pointer(of the same size)instead of this pointer with placement new. example
new (p2) house; //p2 is a pointer to class house (house *p2)
1)according to the above documentation shouldn't my code give a error as i am reusing the old object again after new(this) house ;
but the lifetime of the old object has already ended by reusing the memory
can somebody explain why it is not giving an error? and explain the output.
any help is appreciated.
Here is the code:
class A {
private:
int *anArr;
int id;
public:
A() {
id = 0;
anArr = new int[10];
}
A(int i) {
id = i;
anArr = new int[10];
}
~A() {
delete[] anArr;
std::cout << "Class A id : " << id << " destructor" << std::endl;
}
};
class B {
private:
A *anArr;
public:
B() {
anArr = new A[10];
}
~B() {
std::cout << "Class B destructor" << std::endl;
delete[] anArr;
}
void changeAnElement() {
anArr[2] = A(1);
anArr[2] = A(2);
}
};
int main()
{
B b;
b.changeAnElement();
return 0;
}
Output:
Class A id : 1 destructor
Class A id : 2 destructor
Class B destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
Class A id : 0 destructor
// Gives heap error here
So if I'm not wrong, when I change an element of object array it does not call destructor.
My first question is what happens to old object at the changed index? Does the array in it leak? I thought that I need to call destructor myself to prevent memory leak but it gives heap error.
Second question is I'm getting heap error (Expression: _CrtlsValidHeapPointer(block)) when destructor of the changed object called. I have no idea why, it works fine for the ones created in constructor.
Thanks!
My first question is what happens to old object at the changed index?
An object in an array never goes anywhere. The "old" object remains in that index. You invoke the assignment operator on that object. The assignment operator modifies the object.
Does the array in it leak?
The array that the object pointed to before the assignment does leak, yes.
I thought that I need to call destructor myself to prevent memory leak
You created the object with new[], so you do need to call delete[], which indeed calls the destructors.
but it gives heap error
That's because you forgot to follow the rule of 3 (or of 5).
anArr[2] contains the same pointer that the temporary A(2) contained, but since the destructor of the temporary has already run, it has already deleted the array and the destructor of anArr[2] then tries to delete it again. Which is one of the things that must not be done.
Conclusions:
When you do manual memory management, follow the rule of 3
Don't do manual memory management. Use std::vector or std::array here instead.
What happens to the old object at the changed index?
It is re-assigned. In C++, this line
anArr[2] = A(1);
makes a new temporary object A(1), assigns that value into the existing object anArr[2], and destroys the temporary object. anArr[2] is the same object throughout, only its value changes. Since it is not newly created, it is also not destroyed at this point. But notice that the temporary object was destroyed, and deleted that brand new int[10] that anArr[2] thinks (mistakenly) that it owns.
When the value is a pointer to existing resources that need to be freed, you need to write a user-defined assignment operator, A::operator=(const A&). The "Rule of Three" says that most cases where you need a custom destructor, custom copy constructor, or custom copy assignment operator, you also need both the other two. (Since C++11, move constructor and move assignment are added to that list, making the "Rule of Five").
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;
What would make a field variable become obsolete before entering the destructor upon deletion of the object?
I was a looking for an answer for this problem I'm having on this site and came across this:
Lifetime of object is over before destructor is called?
Something doesn't add up at all: if I've declared a pointer to SomeClass inside another WrapperClass, when I construct the WrapperClass I need to create a new SomeClass and delete it on destruction of the wrapper.
That makes sense and has worked so far.
The pointer is still valid and correct well into the destructor otherwise obviously I wouldn't be able to delete it.
Now my problem is that my field members (both an int and a pointer to a SomeClass array) of WrapperClass are garbage when I call the destructor. I've checked the wrapper object just after construction and the data is fine. The wrapper is actually a pointer in another Main class and the problem occurs when I destruct that Main (which destructs the wrapper) but works fine if I just delete the wrapper from another method in Main.
My paranoia led me to the above mentioned answer and now I'm totally confused.
Anybody care to shed some light on what's really going on here?
EDIT:
Node is the SomeClass.
class WrapperException{};
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
Node** nodes;
public:
Wrapper() : numNodes(0) { nodes = new Node*[SIZE]; }
Wrapper(const Wrapper& other) { throw WrapperException(); }
Wrapper& operator=(const Wrapper& other) { throw WrapperException(); }
~Wrapper() { //calling delete Main gets me here with garbage for numNodes and nodes
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete nodes;
}
};
class MainException{};
class Main {
public:
Main() { wrapper = new Wrapper(); }
Main(const Main& other) { throw MainException(); }
Main& operator=(const Main& other) { throw MainException(); }
~Main() { delete wrapper; }
private:
Wrapper* wrapper;
};
You need to use the Standard library to implement this behaviour.
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
std::vector<std::unique_ptr<Node>> nodes;
public:
Wrapper() : numNodes(0) { nodes.resize(SIZE); }
// No explicit destructor required
// Correct copy semantics also implemented automatically
};
class Main {
public:
Main() : wrapper(new Wrapper()) {}
// Again, no explicit destructor required
// Copying banned for move-only class, so compiler tells you
// if you try to copy it when you can't.
private:
std::unique_ptr<Wrapper> wrapper;
};
This code is guaranteed to execute correctly. When in C++, if you have used new[], delete or delete[], then immediately refactor your code to remove them, and review three times any use of non-placement new- constructing a unique_ptr is pretty much the only valid case. This is nothing but a common, expected outcome of manual memory management.
Since Grizzly isn't answering, I'll put this out there.
Both your Main class and your Wrapper class need properly implemented copy constructors and assignment operators. See The Rule of 3.
The problem is, if your class ever gets copied(which is easy to happen without you even realizing it), then the pointers get copied. Now you've got two objects pointing to the same place. When one of them goes out of scope, it's destructor gets called, which calls delete on that pointer, and the pointed to object gets destroyed. Then the other object is left with a dangling pointer. When it gets destroyed, it tries to call delete again on that pointer.
The lifetime of your wrapper object has ended, but the integer and pointer sub-objects as well as the pointee are still alive. When you invoke delete on the pointer, the pointee's lifetime ends, but the pointer still remains alive. The pointer's lifetime ends after your dtor is complete.
Thus, if your members have become corrupted, there is something else afoot.
Node** nodes;
should be
Node * nodes;
Also the destructor is wrong. It should be:
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete [] nodes;
There might be other problems as well as e.g. you haven't created a copy constructor or assignment operator so that might make it so that the copy of an object then deletes the object for you.
EDIT: changed the destructor...
Let's say i have 2 classes:
class Class1
{
public:
std::vector<CustomClass3*> mVec;
public:
Class1();
~Class1()
{
//iterate over all the members of the vector and delete the objects
}
};
class InitializerClass2
{
private:
Class1 * mPtrToClass1;
public:
InitializerClass2();
void Initialize()
{
mPtrToClass1->mVec.push_back(new CustomClass3(bla bla parameters));
}
};
Will this work? Or the memory allocated in the InitializerClass2::Initialize() method might get corrupted after the method terminates?
Thanks!
In short this will work fine.
The memory being allocated in Initialize is on the heap. This means that changes in the stack do not affect the contents of this memory.
One issue I see with Class1 is that it is not copy safe yet the copy and assignment constructors have not been suppressed.
This can cause a problem because the destructor of Class1 is noted as freeing the memory for all items in mVec. Using the implicit operator this means that you'd end up with 2 instances of Class1 pointing to the same CustomClass3 instances and the second destructor would be double deleting memory. For example
Class c1;
c1.mVec.push_back(new CustomClass3(...));
Class c2 = c1;
In this case the second destructor to run (c1) will be freeing an already deleted CustomClass3 instance. You should disable copy construction and assignment for Class1 to prevent this
class Class1 {
...
private:
Class1(const Class1&);
Class1& operator=(const Class1&);
};
It should work (provided mPtrClass1 is a valid pointer of course).
May I suggest that in your InitializerClass2 that you change the constructor to the following:
InitializerClass2() : mPtrToClass1(NULL){}
~InitializerClass2(){
if( mPtrToClass1 != NULL) delete mPtrToClass1;
}
void Initialize(){
if( mPtrToClass1 == NULL){
mPtrToClass1 = new InitializerClass1();
}
mPtrToClass1->mVec.push_back(new CustomClass3(bla bla parameters) );
}
if you're not going to use RAII, so that you don't get issues with checking the destructor.
As to your question, see where I added in the new operator. YOu're not initializing your variable.