Current Implementation
I have a class containing unique_ptr fields which depend on one other:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor, then construct a new instance on top
~ResourceManager();
ResourceManager* new_this = new(this) ResourceManager();
// Surely this must be the case, right?
// Is there any reason to prefer using either?
assert(new_this == this);
new_this->b_ptr = that.b_ptr;
new_this->c_ptr = that.c_ptr;
return *new_this;
}
unique_ptr<B> b;
unique_ptr<C> c;
};
Use case
The use case here is that I would like to reassign new values to the pointers, whilst keeping the ResourceManager as a stack-allocated variable, or as a non-pointer class member.
With my current setup I imagine using it something like this:
A a, another_a;
ResourceManager r(&a);
// Use r...
// Destroy old ResourceManager and create the new one in place.
r = ResourceManager(&another_a);
The reason this is even a problem is due to the fact that B and C are non-assignable (for e.g. file streams)
Ugly Alternative
An alternative uglier (and dangerous) method would be to explicitly reset the unique_ptr fields crucially in reverse order (remember that C depends on B, and hence must be destructed first), effectively mimicking the default destruction behaviour.
ResourceManager& operator=(ResourceManager&& that) {
// Mimic destructor call (reverse-order destruction)
c_ptr.reset();
b_ptr.reset();
b_ptr = that.b_ptr;
c_ptr = that.c_ptr;
return *this;
}
Note that a wrong implementation would be to simply use the default assignment operator for ResourceManager. This will assign the field in-order which implies in-order destruction of the unique_ptrs, whereas we require reverse-order destruction.
Questions
Is this usage of this pointer with placement new and the explicit destructor call safe?
Must I use the returned new_this pointer as opposed to the original this pointer (for example, if the this pointer technically becomes invalidated after calling the destructor)?
Are there any better suggested ways to achieve this? If add more such unique_ptr fields to the class, I would have to make sure that I add a copy to the assignment operator. For instance, is it possible to call the move constructor instead, like so:
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor
~ResourceManager();
// Move-construct a new instance on top
ResourceManager* new_this = new(this) ResourceManager(that);
return *new_this;
}
Your solution seems overly complex.
I would code it like this:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that)
{
// the order of these moves/assignments is important
// The old value of *(this->c_ptr) will be destroyed before
// the old value of *(this->b_ptr) which is good because *c_ptr presumably
// has an unprotected pointer to *b_ptr.
c_ptr = std::move(that.c_ptr);
b_ptr = std::move(that.b_ptr);
// (a better solution might be to use shared_ptr<B> rather than unique_ptr<B>
return *this;
}
unique_ptr<B> b_ptr;
unique_ptr<C> c_ptr;
};
Note: When the move assignment returns, that will "empty" meaning both that.b_ptr and that.c_ptr are nullptr. This is the expected result of a move assignment.
Or if "reconstructing" the target of the assignment is important (assuming there's extra code not shown in this example that makes it so) I might add a move constructor and a swap method like so:
ResourceManager(ResourceManager&& that)
: b_ptr(std::move(that.b_ptr)),
c_ptr(std::move(that.c_ptr))
{
}
void swap(ResourceManager & that)
{
b_ptr.swap(that.b_ptr);
c_ptr.swap(that.c_ptr);
}
ResourceManager& operator=(ResourceManager&& that)
{
ResourceManager temp(std::move(that));
this->swap(temp);
return *this;
}
Related
I am using the pimpl idiom with a const std::unique_ptr to hold the class implementation. My class needs to support copy construction and copy assignement. What I'd like to do is manually call the copy constructor of the impl class inside the unique_ptr. However, I fail to see how.
#include <memory>
struct potato {
potato();
~potato();
potato(const potato& p);
private:
struct impl;
const std::unique_ptr<impl> _pimpl;
};
struct potato::impl {
int carbs = 42;
};
potato::potato()
: _pimpl(std::make_unique<impl>()) {
}
potato::~potato() = default;
potato::potato(const potato& p) {
// Try to call the copy constructor of impl, stored in unique_ptr, not the
// unique_ptr copy-constructor (which doesn't exist).
_pimpl.get()->impl(p._pimpl); // This doesn't work.
}
I've checked out another question about explicitly calling the copy-constructor on an object. One answer recommended using placement new.
Object dstObject;
new(&dstObject) Object(&anotherObject);
Could I use this in my copy-constructor? If so, how? I don't really understand whats happening there. Thank you.
What I'd like to do is manually call the copy constructor of the impl class inside the unique_ptr
Here lies your error. As you are inside the (copy) constructor of potato, there's no impl object already constructed over which you'd have to "manually" invoke the copy constructor.
Just construct your new impl passing to it a reference to the original impl to copy.
potato::potato(const potato& p)
: _pimpl(std::make_unique<impl>(*p._pimpl) {
}
As for assignment, you can easily forward to the impl assignment operator:
potato &operator=(const potato &p) {
*_pimpl = *p._pimpl;
return *this;
}
You can invoke constructors explicitly on uninitialized storage with the placement new operator, as you mentioned. You can return the storage of an object to an uninitialized state by explicitly calling its destructor.
Here’s a simple implementation of the assignment operator that explicitly invokes the copy constructor and the destructor you already defined as part of your interface:
#include <new>
potato& potato::operator=(const potato& x)
{
if ( this != &x ) { // check for self-assignment!
this->~potato();
new(this) potato(x);
}
return *this;
}
You would probably also want to define a move constructor and overload the assignment operator when the right-hand side is a temporary. That is, overload for potato&& src as well as const potato& src. You could use the swap idiom if your class supports it, or the same code as above, but calling new(this) potato(std::move(src));.
If you have access to the destructor and copy constructor of the class wrapped in a smart pointer, you can do the same trick with them, just dereferencing the smart pointers. You probably don’t want to, though.
The default copy constructor and assignment operator ought to work just fine, if the contents of the class are smart pointers, STL containers, and so on. You probably would want to copy the data referenced by the smart pointers by writing things like *p = x or *p = *q or std::swap, rather than explicit calls to the copy constructor.
Here is my following code. Once the constructor of A is complete, it immediately calls the ~B and deletes the allocated variable. I have the copy constructor and assignment constructor. Should I implement rule of five to prevent this?
EDIT: I have edited my copy and assignment constructor implementations, but still the destructor is being called.
class B
{
public:
C **table;
B()
{
table = new C *[TABLE_SIZE]();
}
B(const B& other)
{
table = new C *[TABLE_SIZE];
memcpy(table, other.table, sizeof(C *)* TABLE_SIZE);
}
B& operator = (const B& other)
{
if (this == &other)
{
return *this;
}
delete[] table;
table = new C *[TABLE_SIZE];
memcpy(table, other.table, sizeof(C *)* TABLE_SIZE);
return *this;
}
~B()
{
delete[] table;
}
}
class A
{
protected:
B funcA();
private:
B _b;
}
A::A()
{
this->_b = this->funcA();
// calls ~B here and destroys table
}
You do have the copy constructor and copy assignment operator implemented, but incorrectly. You implemented them to do exactly what the defaults do, which is of course wrong for your case of owning a dynamically allocated memory stored in a raw pointer. The Rule of Three of course means that you must implement them consistently.
In your case, this most likely means the copy operations must deep-copy the C object:
class B
{
public:
C *table;
B() : table(new C()) {}
B(const B& other) : table(new C(*other.table)) {}
B& operator = (const B& other)
{
if (this == &other)
{
return *this;
}
delete table;
table = new C(*other.table);
return *this;
}
~B()
{
delete table;
}
};
Notice that you default constructor wouldn't even compile - you were assigning a C* into a C**. I changed the code above to use a single allocation (and single-item delete) instead of an array. If you do have an array, the principle stays the same.
Of course, it's preferable to follow the Rule of Zero instead of the Rule of Three—use an appropriate smart pointer if possible. If your real use case is an array, that would be turning table into a std::vector<C>. Then you wouldn't have to supply the copy operations or destructor at all.
If you actually want to share one C among all copies of B, then you'll need to use an appropriate shared-ownership smart pointer instead, such as std::shared_ptr<C>.
Simply put, the temporary instance returned by funcA should be destroyed, that's normal and expected. The fact that your code is not functioning as a result means that your copy constructor and assignment operator are not functioning correctly.
But more fundamentally, you're violating several more important rules than the Rule of Three. You're failing to re-use the existing solution of std::vector. You're violating SRP by tying together memory management and whatever else B does when it's at home. You're failing to use RAII to manage your internal resources- a big exception safety fail.
Basically, the core problem is that you're even attempting to perform these operations. Don't. Just use std::vector<C*> and make the compiler and Standard library vendor implement them for you. They will save you a lot of code, and furthermore, they will be correct in ways that I'm going to guess that you don't know exist yet, like exception safety. The Rule of Three and the Rule of Five (which didn't even exist long enough to become a rule) are both vastly inferior to the Rule of Zero.
Here's B but implemented correctly:
class B {
public:
std::vector<C*> table;
B() : table(TABLE_SIZE) {}
};
Simple, ain't it?
As a side note, I don't know where you're getting your learning materials, but you should burn with fire any source so seriously outdated as to recommend self-assignment checks, and well, any of that code. May as well tell you that 640k of memory is all you'll ever need.
Your constructor is:
A::A()
{
this->_b = this->funcA();
// calls ~B here and destroys table
}
The comment is correct, although the table being destroyed is the table in the temporary object, not the table of _b. Since you fixed your copy-assignment operator this means that _b's table is fine.
The list of steps in executing this constructor is:
Call default constructor of _b
Call funcA, returning a temporary object of type B
Call _b 's assignment operator with that temporary object
Destruct the temporary object.
The constructor could be improved by supplying funcA() directly as initializer for _b, instead of first default-constructing _b then using its assignment operator. (But there is still a temporary object destruction).
There may also be another temporary object created and destroyed in the process of returning from the function, depending on your compiler settings. (usually there would not be).
I want to gain a better understanding of how to implement the RAII idiom with my classes, through an example: What the recommended method is for ensuring pointers are free()'d properly in my class?
I have a class which should exist for the duration of the program. In the spirit of RAII and because I need to pass a reference to this class to other classes, I am holding it in a shared_ptr (not sure it actually needs to be held in a shared_ptr, but for fun, it is).
In the class ctor, I use 2 buffers (pointers) and then loop multiple times malloc()'ing, using the buffer and then free()'ing. The dtor should contain failsafe code to free the buffers, in the event of mishap.
The only way the dtor can see the buffers is if I declare them as class variables, however they are only used in the class ctor.
Example:
class Input
{
private:
PSOMETYPE buffer1;
public:
Input();
~Input();
}
Input::Input() : buffer1(NULL)
{
for(blahblah)
{
buffer1 = (PSOMETYPE)malloc(sizeof(SOMETYPE));
// Do work w/buffer1
if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
}
}
Input::~Input()
{
if(buffer1 != NULL) { free(buffer1); buffer1 = NULL }
}
Considering I only use the buffer in the ctor, does it make sense to declare it as a private class variable? If I declare it in the scope of the ctor, the dtor will have no knowledge as to what it is to free.
I know this is a trivial example, and honestly I could implement this as easily forgetting about using a smart pointer to reference my class and having a blank dtor, just free()'ing as I'm doing inside the loop. I have no mentor or schooling, and I'm uncertain of when the RAII idiom should be followed.
The spirit of RAII would be to use a local object to manage the locally allocated object, rather than artificially tying its lifetime to the object being constructed:
class Input
{
// no pointer at all, if it's only needed in the constructor
public:
Input();
// no explicit destructor, since there's nothing to explicitly destroy
};
Input::Input()
{
for(blahblah)
{
std::unique_ptr<SOMETYPE> buffer1(new SOMETYPE);
// or, unless SOMETYPE is huge, create a local object instead:
SOMETYPE buffer1;
// Do work w/buffer1
} // memory released automatically here
}
You should only ever have to use delete (or free, or whatever) yourself if you're writing a class whose purpose is to manage that resource - and usually there's already a standard class (such as a smart pointer or a container) that does what you want.
When you do need to write your own management class, always remember the Rule of Three: if your destructor deletes something, then the default copying behaviour of the class will almost certainly cause a double delete, so you need to declare a copy constructor and copy-assignment operator to prevent that. For example, with your class I could write the following incorrect code:
{
Input i1; // allocates a buffer, holds a pointer to it
Input i2(i1); // copies the pointer to the same buffer
} // BOOM! destroys both objects, freeing the buffer twice
The simplest way to prevent this is to delete the copy operations, so code like that will fail to compile:
class Input {
Input(Input const&) = delete; // no copy constructor
void operator=(Input) = delete; // no copy assignment
};
Older compilers may not support = delete; in which case you can get almost the same effect by declare them privately without = delete, and not implementing them.
Sorry about the title. I wasnt sure what to name it. If any mods are reading and they understand the question then please rename if needed too.
Say you create a new variable (varOne).
Inside the varOne code, other variables are created as new (varTwo, varThree).
If you call delete on varOne, will varTwo and varThree be deleted, or do you need to delete them AND delete varOne?
You only need to delete varTwo and varThree, because when you fall out of varOne's destructor, the delete you used to invoke varOne's destructor will clean up that instance of varOne.
In other words, in the example below, varOne is Foo, varTwo is m_i, and varThre is m_c:
class Foo
{
public:
Foo() : m_i( new int ), m_c( new char ) { }
~Foo() { delete m_i; delete m_c; }
// don't forget to take care of copy constructor and assignment operator here!!!
private:
int* m_i;
char* m_char;
};
main()
{
Foo* p = new Foo;
delete p;
}
Also make sure that when you do this, you follow The Rule of Three or your program will suffer memory problems. (In other words, if you are doing memory allocation in your constructor, be sure you either override or delete the default copy-constructor and assignment operators).
You have to delete them and delete varOne seperately, but actually the constructor of varOne should allocate those variables and the destructor should deallocate them if they have to be on the heap for some reason. It would be better to just store them by value and be rid of new and delete for good.
I'm not 100% sure what you mean, but in general, anything that you allocate with new, you have to individually deallocate with delete.
If you mean this in the context of a C++ class, you will need to manually delete varOne and varTwo of the destructor.
Use a smart pointer, and never ever ever delete anything in your own code.
I'm not sure how to understand your question, since you don't new a variable (all variables are static, automatic or member variables) but objects (the pointers you get from new will however usually assigned to use used to initialize variables, maybe that's what you meant?). Therefore I'll give a general answer ad hope that what you asked for is included.
First, as a basic rule, every object you allocate with new has to be deallocated explicitly with delete. However, the delete might be hidden in another object, like shared_ptr and scoped_ptr/unique_ptr from boost or C++11, or auto_ptr in earler versions of C++.
If your object contains subobjects, it's usually best to make them direct members, so you don't allocate them with new at all (indeed, that's a general rule in C++: If you don't absolutely have to dynamically allocate, don't). That is, you'd write your class as
class X
{
public:
// ...
private:
Type1 subobject1;
Type2 subobject2:
};
and don't have to mess with new/delete for the sub objects at all. However if you need to dynamically allocate the objects, you also have to delete them, e.g.
class X
{
public:
X()
{
subobject1 = new Type1();
try
{
subobject2 = new Type2();
}
catch(...)
{
delete subobject1;
}
}
~X()
{
delete subobject2;
delete subobject1;
}
// ...
private:
X(X const&); // disabled
X& operator=(X const&); // disabled
Type1* subobject1;
Type2* subobject2;
};
Note the rather complicated code in X's constructor to make sure the object is correctly cleaned up even in case of an exception. Also note that you also have to implement copy construction and assignment or disable them by making them private and unimplemented (note that C++11 offers the special syntax = delete to disable them). You can save yourself a lot of the trouble by using a smart pointer (but you still have to take care about copy construction and assignment, at least with the usual smart pointers):
class X
{
public:
X():
subobject1(new Type1()),
subobject2(new Type2())
{
}
private:
X(X const&) = delete; // disabled
X& operator=(X const&) = delete; // disabled
std::unique_ptr<Type1> subobject1;
std::unique_ptr<Type2> subobject2;
};
Here I've used C++11's unique_ptr (and consequently also used C++11 syntax for removing copy constructor and assignment operator). Note that on first impression this code seems to have no delete at all; however those deletes are actually hidden in the destructor of unique_ptr. Also note that now the explicit exception handling in the constructor is no longer needed; since the deleting is done in the destructors of the unique_ptrs, C++'s exception handling rules for constructors automatically take care of this.
myClassVar = MyClass(3);
I expected destructor being called on the previously created myClassVar on the left.
But it is actually being called on the new object that's created by MyClass(3).
My full test code and output follows..
edit
How do I fix the problem?
Implement an assignment operator?
MyClass actually has pointers, and MYSQL_STMT*, I wonder how should I deal with MYSQL_STMT* variable.
I just need MyClassVar(3) object not the MyClassVar() which was first created when ClientClass object was created.
I came across this situation fairly often, and wonder if there's a good way to do it.
#include <stdio.h>
class MyClass
{
public:
MyClass() { printf("MyClass %p\n", this); }
MyClass(int a) { printf("Myclass(int) %p\n", this); }
~MyClass() { printf("~MyClass %p\n", this); }
private:
int mA;
};
class ClientClass
{
public:
void Foo()
{
printf("before &myClassVar : %p\n", &myClassVar);
myClassVar = MyClass(3); // this is the important line
printf("after &myClassVar : %p\n", &myClassVar);
}
private:
MyClass myClassVar;
};
int main()
{
ClientClass c;
c.Foo();
return 0;
}
MyClass 0x7fff5fbfeba0
before &myClassVar : 0x7fff5fbfeba0
Myclass(int) 0x7fff5fbfeb70
~MyClass 0x7fff5fbfeb70 // <--- here destructor is called on the newly created object
after &myClassVar : 0x7fff5fbfeba0
~MyClass 0x7fff5fbfeba0
Here's how the critical line breaks down:
myClassVar = MyClass(3);
First, MyClass(3) calls constructor and returns the object.
Second, myClassVar = copies the object to myClassVar.
Then the statement ends. The object (which is an immediate) is dead, and thus the destructor is invoked.
EDIT :
As for how to get around this. The only way I can think of is to use a placement new. I'm not sure if there's a better solution other than making a "set" method.
myClassVar = MyClass(3);
myClassVar continues to exist after this line. The lifetime of MyClass(3) ends at the semicolon.
As the other posts mentioned the object with the custom constructor MyClass(3) gets destroyed after the assignment operation myClassVar = MyClass(3). In this case you do not need a custom assignment operator because the compiler generated one copies the member mA to the already existing object myClassVar.
However since MyClass defines its own destructor you should adhere to the rule of three, which mandates that in such a case you should implement a custom assignment operator as well.
Responding to your edit: how do you fix what problem? It's not clear
what the problem is. If your class needs a destructor (and there's no
polymorphism in play), it probably needs both an assignment operator and
a copy constructor. Similarly, when "tracking" construcctions and
destructions, you should probably provide both as well, since they will
be called.
Otherwise: if the problem is that you're constructing and then
assigning, rather than constructing with the correct value immediately,
the simple answer is "don't do it". The compiler does what you tell it
to. If you write:
MyClass var;
var = MyClass(3);
you have default construction, followed by the construction of a
temporary, assignment, and the destruction of the temporary. If you
write:
MyClass var(3);
or
MyClass var = 3;
you only have one construction. (Note that despite appearances, there
is no assignment in the last snippet. Only construction.)
For class members, this difference appears in the way you write the
constructor:
ClientClass::ClientClass() { var = MyClass(3); }
is default construction, followed by creation, assignment and
destruction of a temporary;
ClientClass::ClientClass() : var( 3 ) {}
is just construction with the correct value. (Rather obviously, this
second form is preferred.)