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.
Related
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;
I'm a beginner to c++ so there are a lot of things quite not clear in my mind.
I have this code I need to write and in a class I make a constructor.
However, I don't need any parameters because I read from a file-stream inside the constructor. So my questions are:
1.Can I make a constructor like this:
class myClass {
private:
string title;
string organizer;
public:
myClass() {
title = stringRead();
organizer = stringRead();
}
}
where stringRead() is a function I have written to read from my file??
2.How do I call it afterwards when I need it? I know that the default constructror is being called like that:
myClass A;
A = myClass();
Is it the same?
3.If I have a pointer, how do I call the constructor again? This doesn't seem like it should be right...
myClass *B;
B = myClass();
Thanks in advance! =D
1) This constructor will work but you should favor using an initialization list (assuming stringRead() isn't a member function of myClass
class myClass {
private:
string title;
string organizer;
public:
myClass()
: title(stringRead()),
organizer(stringRead())
{ }
};
2) myClass A; is what you should be doing. You could alternatively have auto A = myClass(); which, after optimizations, will be the same thing. Without optimizations a temporary will be constructed, and then A will be move constructed from it, so this won't work with unmovable objects (your object is movable)
3) If you want to use a raw pointer then you would use
myClass *ptr = new myClass;
// bunch of code
delete ptr;
However, you'd be better using a smart pointer to control its lifetime. This way you won't need to manually delete
std::unique_ptr<myClass> ptr(new myClass);
or make_unique in c++14
auto ptr = std::make_unique<myClass>();
And of course use a shared_ptr if you have shared ownership
I think it's OK to assign the value returned by a function to a member of a class.
You can initialize it as you suggested (with myClass A;)
When you use pointers, you need myClass *k=new myClass();. You should remember to delete the object you created with delete k;.
Your constructor is fine, so long as the functions used within it are globals or static functions of this or another class.
myClass A; will invoke the constructor you have written.
To use a pointer, you need B = new myClass(). That will also call the same constructor. Don't forget to delete B at some point else you'll leak memory.
Do bear in mind that if an exception is thrown in a constructor then the destructor is not called.
Yes, you can, but it might not be the best approach. Reading from input can fail, failure in a constructor is often a non-recoverable event you'll want to handle. A good approach is reading the values outside the costructor, handling errors and calling the constructor only when you have "everything ready". Like this:
class myClass {
private:
string _title;
string _organizer;
public:
myClass(const string &title, const string &organizer) {
_title = title;
_organizer = organizer;
}
or, by using a more idiomatic C++ initializer list:
class myClass {
private:
string _title;
string _organizer;
public:
myClass(const string &title, const string &organizer):
_title(title), _organizer(organizer) {}
}
and then, somewhere else:
string title = stringRead();
string organizer = stringRead();
myClass A(title, organizer);
No, in this snippet:
myClass A;
A = myClass();
two different things happen: at line 1 the default constructor is called; at line 2, a temporary object is constructed (again, by calling the default constructor) and then assigned to A using the (rval for C++11) copy operator. This expression:
myClass A;
calls the default constructor. If you have parameters:
myClass A(title, organizer);
Nope, this does not even work. A pointer is not an object, you have to allocate the object. At that point, you can get a pointer to it:
myClass A;
myClass *B = &A;
you could also resort to dynamic allocation:
myClass *B = new myClass;
in this case, either remember to call delete B somewhere else or wrap B in a smart pointer:
std::unique_ptr<myClass> B(new myClass());
I am trying to understand how to give back memory if one class creates another class.
I have
Clas A;
Then another class that allocate memory for Class A:
class B{
private:
A* data;
public:
// Allocating new memory
B (){
A* data = new A();
//giving memory back
~B(){
delete data; };
};
And when I execute the code in main function it just crashes. What am doing wrong? I am a bit lost here.
Thanks.
Get rid of the redundant A* in the constructor. What this does is create a new, local variable with the same name as your class member. So the real B::data never gets anything assigned to it, and when you try to delete it, things blow up. To add insult to injury, the new A() you assign to the local data will be leaked (well; it would be leaked if the program didn't crash).
class B{
private:
A* data;
public:
// Allocating new memory
B (){
data = new A();
}
//giving memory back
~B(){
delete data;
}
};
That solves the immediate problem, but as juanchopanza noted in the comments, you will still run into problems if you try to copy this object.
Here's the RAII / Rule of Zero route (assuming your compiler supports C++11)
class A {};
class B {
private:
std::unique_ptr<A> data;
public:
B() : data(new A) {
}
};
The RAII handle in this case a unique_ptr will take care of deallocation for you. Implementing it this means the compiler defined copy constructor, copy assignment operator, move constructor, move assignment operator and destructor will all work fine right out the box.
I've been meddling around, testing for memory leaks with Intel Inspector, when I noticed something that should not be. I inherit from std::vector which is not supposed to have a virtual destructor, I have an extra member in the derived class, I do dynamic memory allocation on it, in main I create a derived class on the heap, cast to base class, call delete... and no memory leak is detected??? By all logic, I should get a memory leak.
template <typename T>
class DynamicArray : public std::vector<T> {
public:
DynamicArray() : children(nullptr) {
children = new int(50);
}
~DynamicArray() {
if (children) delete children;
}
DynamicArray& operator<<(const T& value)
{
push_back(value);
return *this;
}
private:
int *children;
};
int main() {
DynamicArray<int> *pArray = new DynamicArray<int>;
(*pArray) << 4 << 5;
static_cast<std::vector<int>*>(pArray);
delete pArray;
}
pArray is still of type DynamicArray<int> and wiil call the right destructor, this would likely leak:
std::vector<int>* wrong = static_cast<std::vector<int>*>(pArray);
delete wrong;
edit: as Ben Voigt correctly mentioned, this last code snippet actually undefined behavior since the destructor of std::vector is not virtual. So it is not even guaranteed that this will leak
This expression has no side-effects:
static_cast<std::vector<int>*>(pArray);
In your code, the delete and new actually match perfectly.
Also, this line allocates ONE int, so you may not notice it in your memory analysis:
children = new int(50);
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...