I have a C++ class with a private "pointer to vector" member pV, I assign a new vector to it in the constructor...
pV = new vector<FMCounter>(n, FMCounter(arg1))>;
However when I delete in the destructor of the class
delete pV;
I get a segfault and a message that I'm trying to free pv that wasn't allocated in the first place. I checked that pV->size() was 4K something, so I am sure it was allocated memory by new.
Pointer members with ownership semantics (allocating in constructor and deallocating in destructor) usually require to write a custom copy constructor and assignment operator (usually known as the Rule of Three), as the compiler generated ones will just copy the pointer member and not its underlying object. So if you at some point copy your containing object, you end up with two objects having the same pointer as member and the one destroyed secondly tries to delete an already deleted pointer.
At the simplest you should make sure your copy constructor does something like
TheClass::TheClass(const TheClass &rhs)
: pV(new vector<FMCounter>(*rhs.pV))
{
}
and your assigment operator does something like
TheClass& TheClass::operator=(const TheClass &rhs)
{
*pV = *rhs.pV
return *this;
}
Related
In my assignment operator method I first destroy any resources that the object manages, and then assign, so:
struct Animal
{
int aNumber;
int * buffer;
Animal() { buffer = new int[128]; }
Animal& operator= (Animal& other)
{
if (this != &other){
delete [] buffer;
//this->~Animal(); // I'm wondering if I can call this instead of deleting buffer here.
aNumber = other.aNumber;
}
~Animal() { delete[] buffer;}
};
The reason I'm asking this is so that instead of rewriting the deleting code, I can just have it in one place. Also, I don't think that calling the destructor deallocates the memory, so when I assign aNumber after calling the destructor, I think it's OK. When I say the memory isn't deallocated I mean for example if I had a vector<Animal>, and the vector called the copy assignment operator for vector[0], vector[0] Animal would call its own destructor and then assign aNumber, but the memory is managed by vector (it's not deallocated). Am I right that the memory isn't deallocated?
After a destructor call the region of memory that held the object is just raw memory.
You can't use the result of just assigning to apparent members there.
It needs a constructor call to re-establish an object there.
But don't do this.
It's fraught with dangers, absolutely hostile deadly territory, and besides it's smelly and unclean.
Instead of
int* buffer;
Animal() { buffer = new int[128]; }
do
vector<int> buffer;
and expand that buffer as necessary as you add items to it, e.g. via push_back.
A std::vector automates the memory management for you, and does it guaranteed correctly. No bugs. Much easier.
In other news, the signature
Animal& operator= (Animal& other)
only lets you assign from non-const Animal objects specified with lvalue expressions (i.e. not temporaries), because only those can be bound the formal argument's reference to non-const.
One way to fix that is to add a const:
Animal& operator= (Animal const& other)
which communicates the intention to not modify the actual argument.
I'm wondering if I can call [the destructor] instead of deleting buffer here.
You may not.
so when I assign aNumber after calling the destructor, I think it's OK
It is not OK. An explicit destructor call ends the lifetime of the object. You may not access members of an object after its lifetime has ended. The behaviour is undefined.
Am I right that the memory isn't deallocated?
You are right, but that doesn't matter.
The reason I'm asking this is so that instead of rewriting the deleting code, I can just have it in one place.
That can be achieved by writing a function that frees the resources, and call that function from both the assignment operator and the destructor.
I found the following code while reading placement new operator.
#include <iostream>
using namespace std;
class MyClass {
public:
// Placement new operator
void* operator new (size_t sz, void* v) {
cout << "Placement new invoked" << endl;
return v;
}
~MyClass() {
// Cleanup
}
};
int main()
{
// Create a buffer to store the object
int buffer[16];
cout << "Starting address of my buffer = " << &buffer << endl;
// Create the object. Use placement new
MyClass* obj = new (buffer) MyClass();
cout << "Location of my object = " << obj << endl;
// Don't delete object created with placement delete
// Call the destructor explicitly
obj->~MyClass();
}
I have few questions related to delete object which was created using placement new:
what is the clean up code needs to write in destructor in order to
free memory which was occupied obj in buffer memory.
is it not needed to define placement delete, if yes whether it needs to be inside destructor or outside destructor. If it is outside destructor how it will be called ?
Regular new does two things:
allocate memory for your object
construct your object in that memory space.
Placement new means you manage one of those and the other is managed as before.
You allocate / provide the memory for your object
Constructor is called in that memory space.
The reverse is delete of which the regular delete does the following:
Invoke the destructor of the object to clean-up
Free the memory that was allocated for it.
Note that they are done in reverse order for obvious reasons. You cannot free the memory that contains information about what needs to be cleaned up, unti you have finished using that memory. Whereas in construction you need to get hold of the memory first.
In what you call placement delete but is really the reverse of placement new, you need to perform the first step of destruction but not the second. Thus you call the object's destructor, and then you can free up the memory it uses / use it for something else.
The most common example of usage of placement new is in the implementation of std::vector which requires a contiguous buffer for its data, and which lets you reserve ahead (and if you don't it will probably do it for you). That part allocates the memory but does not construct the objects in it. Thus when they are constructed later, placement new is used.
what is the clean up code needs to write in destructor in order to free memory which was occupied obj in buffer memory
The destructor should just do what any destructor does: clean up any resources managed by the object. In this case, it doesn't manage any resources, so there's no need to do anything.
It shouldn't do anything special according to how the storage for the object itself was allocated. Managing that storage is the job for custom new and delete operators, when required.
is it not needed to define placement delete
No. Placement-new is used to construct an object in storage that you're managing yourself, and it's your responsibility to free that storage yourself. In this case, the storage is automatic, so it's automatically freed when the function exits.
Just as the allocator for placement-new does nothing (just returning the provided pointer to pre-allocated storage), so the corresponding deallocator would do nothing; and so it doesn't exist. You just need to destroy the object by calling its destructor directly, before disposing of the storage yourself.
The first thing to ask is: what are you trying to do? If you
define a placement operator new in a class, then that is the
only operator new which will be found when you write new
MyClass; you must always specify the extra arguments. And in
almost every case where you define a class specific operator
new, you should also define a class specific operator delete;
otherwise the global operator delete function will be called
when you write delete p, and that generally won't work.
If your goal is to systematically require separation of
allocation and initialization, and that is why you are defining
a member operator new, then you can provide a no-op operator
delete; if the constructor of the class can throw, then you'll
also want to provide a placement operator delete, since this is
what will be called if the constructor of a newed object exits
via an exception. There is no other way to call it, however.
When providing placement operator new, you must provide
a default operator delete which does the right thing; and when
providing several operator new for the same type, you need to
memorize somehow in each allocation which one was called, in
order to dispatch in the non-placement operator delete.
And by the way, just allocating a buffer as a local variable
does not guarantee sufficient alignment for anything but the
declared buffer type.
EDIT:
Just an example of what would be needed for the operator
delete functions (which must be members):
void operator delete( void* p ) {}
void operator delete( void* p, void* ) {}
I'm new to this website, and to the programming world. So, please be patient with me :)
I read about the rule of three, and I understood how the Copy Constructor and the Assignment operator work.
So I understood that, the default ones, provided by C++, provide a shallow-copy (or memberwise) of the objects.
My question is ... if the class has a member pointer (which points to dynamic allocated memory), the default Assignment Operator, will only copy the address held in the pointer from the original object to the pointer of the object is being assigned to. But won't this create a memory leak?
For example, the followind code:
class GCharacter //Game Character
{
private:
std::string name;
int capacity; //the capacity of our tool array
int used; //the nr of elements that we've actually used in that tool array
std::string* toolHolder; //string pointer that will be able to reference our ToolArray;
public:
static const int DEFAULT_CAPACITY = 5;
//Constructor
GCharacter(std::string n = "John", int cap = DEFAULT_CAPACITY)
:name(n), capacity(cap), used(0), toolHolder(new string[cap])
{
}
}
int main()
{ GCharacter gc1("BoB", 5);
GCharacter gc2("Terry", 5);
gc2 = gc1;
GCharacter gc3 = gc1;
return 0;
}
So, in this code, when gc1 is created, gc1.toolHolder holds the address of some dynamic allocated memory of 5 strings. Let's say, address 125. After this, gc2 is created and dynamic allocates memory for 5 strings, and let's say gc2.toolHolder holds the address 135.
The next line of code, calls the default assignment operator, and provides a shallow-copy from every member of gc1 to gc2. This means that now the pointer gc2.toolHolder also holds the address 125, and we no longer can access the memory at address 135. So the default assignment operator, in situations like these, creates memory leaks? ... or I understood something wrong??
Also, another question, in the case of the default Copy Constructor, because it is called only on objects that don't already exist, it means that gc3.toolHolder won't get the chance to allocate new memory, let's say, at address 145? It will just receive the address stored in gc1.toolHolder?
To try to be more specific... what I'm asking is if it's the same case as above, except we just have both pointers gc3.toolHolder and gc1.toolHolder, reference the same address 125, without gc3.toolHolder dynamic allocating new memory of 5 strings.
Long story short, when we instantiate a class that has a pointer member variable which points to dynamic allocated memory, will the default assignment operator cause a memory leak? and the default copy constructor share pointers to the same allocated memory?
Thank you for your time!
The memory leak you have is the lack of a destructor which frees the memory allocated with new in the constructor, you need:
~GCharacter() { delete[] toolHolder; }
If you add this, you will see the second problem you have: The default generated copy-ctor and assignment just copy/assign the pointer, hence when you have a copy and both original and copy go out of scope, they will both try to delete the memory. This double-free is of course the much bigger problem than the memory leak as it will most likely corrupt the memory.
That said, you want to add your own copy-ctor and assignment operator and implement it correctly. In this case it means to allocate memory for the copy's toolHolder. Generally, read about the Rule of Five for when to implement which set of methods for your class.
I have the following constructors, destructor, and assignment operator in one of my classes. I am wondering if it leaks memory.
MenuItem::MenuItem() {
menu_items = new vector<MenuItem>;
}
MenuItem::MenuItem(const MenuItem &other) {
menu_items = new vector<MenuItem>(*other.menu_items);
}
MenuItem::~MenuItem() {
menu_items->erase(menu_items->begin(), menu_items->end());
delete menu_items;
}
MenuItem & MenuItem::operator= (const MenuItem &other) {
*menu_items = *other.menu_items;
return *this;
}
My main concern is the assignment operator. I looked at some documentation and found this: The container preserves its current allocator, which is used to allocate storage in case of reallocation. Any elements held in the container before the call are either assigned to or destroyed. To me this means that my assignment is safe from memory leaks, but I've misinterpretted the documentation before. Thanks for the help.
The code looks good, but don't dynamically allocate the vector. A vector dynamically allocates its elements anyway, so there's little use of allocating the container itself. If you make the vector a data member your code reduces to:
struct MenuItem
{
std::vector<MenuItem> menu_items;
};
Everything else will be implicitly generated by the compiler. If you really have a valid reason for newing the vector, the only changes I recommend are using constructor initializer lists for initialization and not calling vector::erase in the destructor because it is unnecessary.
MenuItem::MenuItem()
: menu_items(new vector<MenuItem>())
{}
MenuItem::MenuItem(const MenuItem &other)
: menu_items(new vector<MenuItem>(*other.menu_items))
{}
MenuItem::~MenuItem()
{
delete menu_items;
}
There is no memory leak in your program because of the assignment operator. However, it feels very strange to allocate the vector on the heap, do you have any reason for doing so?
In reality, there could be a memory leak if the allocator of the contained object throws an exception. Let me explain
you call the copy constructor
it tries to instantiate a new vector calling new; this could throw an exception and this would be fine, no problem at all
the call to operator new succedes, but the allocator of the contained object throws an exception; you don't catch the exception in the constructor, the constructor throws and no destructor is called -> memory leak as for the (possibly not empty) vector you allocated.
If you are using C++11 you can solve the issue by delegating to the default constructor from within the copy constructor, as in:
MenuItem::MenuItem(const MenuItem &other) : MenuItem(){
*menu_items = *other.menu_items;
}
If you do so, when you reach the assignment of *menu_items the object is fully constructed (by : MenuItem(), so to say) and if this throws the destructor gets called and delete menu_items gets executed.
If you are not using C++11
MenuItem::MenuItem(const MenuItem &other) : menu_items(NULL) {
try{ menu_items = new vector<MenuItem>(*other.menu_items); }
catch(...){delete menu_items;}
}
which is probably a betters solution anyway.
What you cite from the documentation is of no concern in this context, it means that the container will use the same function to allocate the objects it contains.
That looks fine, in the sense of having no memory errors: you're deleting the vector on destruction (although there's no need to erase the contents first), and implementing copy semantics so that each vector is owned by exactly one object. The vector also has correct copy semantics (since otherwise it would be to dangerous to use), so your assignment operator is correct.
However, there's no point in dynamically allocating the vector at all. Why not make it a member variable? Then you can simplify all that code to the following:
In the use of "placement new" it is suggested to call the constructor and destructor explicitly.
In this case will the objects initialized in the initializer section of a class also get properly constructed?
Same too with explicitly calling the destructor? Do the member objects get destroyed properly?
In the use of "placement new" it is
suggested to call the constructor and
destructor explicitly.
It's not correct to say that "you call constructor explicitly", as constructors don't have names ($12.1/1).
In this case will the objects
initialized in the initializer section
of a class also get properly
constructed?
Yes. Why do you doubt it? Placment new only means that the new operator will not allocate any memory, rather will use the memory which you pass in placement new, to construct the object. The object gets constructed in the memory which you pass.
Same too with explicitly calling the
destructor? Do the member objects get
destroyed properly?
Yes.
In the use of "placement new" it is suggested to call the constructor and destructor explicitly.
I don't think so. It will say that you need to call the destructor explicitly.
In this case will the objects initialized in the initializer section of a class also get properly constructed?
Apart from the supplying of the memory all other aspects of placement new are the same as normal new. So rather than dynamically allocating memory it just uses the supplied pointer.
Same too with explicitly calling the destructor?
You can (if you feel naught) call the destructor explicitly on any object. It will call the user defined (or compiler generated) class destructor as normal. The reason you need to explicitly do it for objects created via placement new is that you can call delete on these objects. This is because delete assumes the object was created in dynamically allocated memory and tries to re-cycle that memory after the destructor has been called.
Do the member objects get destroyed properly?
Yes.
If we think of new like this:
// not real code
template<class T> T* new(void* location = NULL) (ArgumentsForT)
{
// If you do not provide location (normal usage)
// then we allocate some memory for you.
if (location == NULL)
{ location = malloc(sizeof(T)); // Use of malloc() is just an example
}
((T*)location)->Constructor(ArgumentsForT);
return (T*)location;
}
So placement new will work just like normal new.
Looking at the call to delete
template<typename T> void delete(T* obj)
{
if (obj != NULL)
{
obj->~T();
free(obj);
}
}
The trouble here is that delete can not tell if the memory was allocated by new or if the memory was allocated by the user and passed into new (placement new). So it always calls free on the memory. If you used placement new then you may not have dynamically allocated the memory (or the memory is still being used for something else).
char x[sizeof(T)]; // don't do this (memory may not be aligned correctly).
T* obj = new (x) T();
delete obj; // FAIL. The memory was not dynamically allocated.
// Delete will try and re-claim this memory for re-yse
// Even if the memory is local.
// This is why on placement new you need to call the destructor
obj->~T();