calling copy constructor and operator= for class data members - c++

Below is an example code (for learning purpose only). Classes A and B are independent and have copy contructors and operators= .
class C
{
public:
C(string cName1, string cName2): a(cName1), b(new B(cName2)) {}
C(const C &c): a(c.a), b(new B(*(c.b))) {}
~C(){ delete b; }
C& operator=(const C &c)
{
if(&c == this) return *this;
a.operator=(c.a);
//1
delete b;
b = new B(*(c.b));
//What about this:
/*
//2
b->operator=(*(c.b));
//3
(*b).operator=(*(c.b));
*/
return *this;
}
private:
A a;
B *b;
};
There are three ways of making assignment for data member b. In fact first of them calls copy constructor. Which one should I use ? //2 and //3 seems to be equivalent.

I decided to move my answer to answers and elaborate.
You want to use 2 or 3 because 1 reallocated the object entirely. You do all the work to clean up, and then do all the work to reallocate/reinitialized the object. However copy assignment:
*b = *c.b;
And the variants you used in your code simply copy the data.
however, we gotta ask, why are you doing it this way in the first place?
There are two reasons, in my mind, to have pointers as members of the class. The first is using b as an opaque pointer. If that is the case, then you don't need to keep reading.
However, what is more likely is that you are trying to use polymorphism with b. IE you have classes D and E that inherit from B. In that case, you CANNOT use the assignment operator! Think about it this way:
B* src_ptr = new D();//pointer to D
B* dest_ptr = new E();//pointer to E
*dest_ptr = *src_ptr;//what happens here?
What happens?
Well, the compiler sees the following function call with the assignment operator:
B& = const B&
It is only aware of the members of B: it can't clean up the no longer used members of E, and it can't really translate from D to E.
In this situation, it is often better to use situation 1 rather than try to decern the subtypes, and use a clone type operator.
class B
{
public:
virtual B* clone() const = 0;
};
B* src_ptr = new E();//pointer to D
B* dest_ptr = new D();//pointer to E, w/e
delete dest_ptr;
dest_ptr = src_ptr->clone();

It may be down to the example but I actually don't even see why b is allocated on the heap. However, the reason why b is allocate on the heap informs how it needs to be copied/assigned. I think there are three reasons for objects to be allocated on the heap rather than being embedded or allocated on the stack:
The object is shared between multiple other objects. Obviously, in this case there is shared ownership and it isn't the object which is actually copied but rather a pointer to the object. Most likely the object is maintained using a std::shared_ptr<T>.
The object is polymorphic and the set of supported types is unknown. In this case the object is actually not copied but rather cloned using a custom, virtual clone() function from the base class. Since the type of the object assigned from doesn't have to be the same, both copy construction and assignment would actually clone the object. The object is probably held using a std::unique_ptr<T> or a custom clone_ptr<T> which automatically takes care of appropriate cloning of the type.
The object is too big to be embedded. Of course, that case doesn't really happen unless you happen to implement the large object and create a suitable handle for it.
In most cases I would actually implement the assignment operator in an identical form, though:
T& T::operator=(T other) {
this->swap(other);
return *this;
}
That is, for the actual copy of the assigned object the code would leverage the already written copy constructor and destructor (both are actually likely to be = defaulted) plus a swap() method which just exchanges resources between two objects (assuming equal allocators; if you need to take case of non-equal allocators things get more fun). The advantage of implementing the code like this is that the assignment is strong exception safe.
Getting back to your approach to the assignment: in no case would I first delete an object and then allocate the replace. Also, I would start off with doing all the operations which may fail, putting them into place at an appropriate place:
C& C::operator=(C const& c)
{
std::unique_ptr tmp(new B(*c.b));
this->a = c.a;
this->b = tmp.reset(this->b);
return *this;
}
Note that this code does not do a self-assignment check. I claim that any assignment operator which actually only works for self-assignment by explicitly guarding against is not exception-safe, at least, it isn't strongly exception safe. Making the case for the basic guarantee is harder but in most cases I have seen the assignment wasn't basic exception safe and your code in the question is no exception: if the allocation throws, this->b contains a stale pointer which can't be told from another pointer (it would, at the very least, need to be set to nullptr after the delete b; and before the allocation).
b->operator=(*(c.b));
(*b).operator=(*(c.b));
These two operations are equivalent and should be spelled
*this->b = *c.b;
or
*b = *c.b;
I prefer the qualified version, e.g., because it works even if b is a base class of template inheriting from a templatized base, but I know that most people don't like it. Using operator=() fails if the type of the object happens to be a built-in type. However, a plain assignment of a heap allocated object doesn't make any sense because the object should be allocated on the heap if that actually does the right thing.

If you use method 1 your assignment operator doesn't even provide the basic (exception) guarantee so that's out for sure.
Best is of course to compose by value. Then you don't even have to write your own copy assignment operator and let the compiler do it for you!
Next best, since it appears you will always have a valid b pointer, is to assign into the existing object: *b = *c.b;

a = c.a;
*b = *c.b;
Of course, if there is a possibility that b will be a null pointer the code should check that before doing the assignment on the second line.

Related

Unique Pointers and The Rule of 3

I often find myself using unique pointers in C++ when I want polymorphic behaviour. I typically implement pure abstract classes something like the below:
class A {
public:
virtual A* clone() const = 0; // returns a pointer to a deep copy of A
// other methods go here
};
The clone method comes in handy when I want to embellish another class with its own instance of A, for example:
#include <memory>
class B {
private:
std::unique_ptr<A> a_ptr;
public:
// ctor
B(const A& a) {
a_ptr = std::unique_ptr<A>(a.clone());
//...
}
// copy ctor
B(const B& other) : B(*other.a_ptr) {}
};
I invariably end up implementing the copy constructor in B to avoid a compiler error (MSVC gives a vague message about attempting to reference a deleted function), which makes complete sense because of the unique pointer. My questions can be summarised as follows:
Do I actually need the copy constructor in B? Perhaps there's a better pattern that would allow me to avoid it altogether.
If yes to 1, can I stop there? Will I ever need to implement the other default functions? I.e. is there any scenario where I need a default constructor and destructor also?
In practice, whenever I feel I need to implement the default functions, I typically implement a move-constructor alongside the other three; I usually use the copy-and-swap-idiom (as per GManNickG's answer in this thread). I assume this wouldn't change anything, but maybe I am wrong!
Thanks a lot!
First, I think the signature of your clone function could be
virtual std::unique_ptr<A> clone() = 0;
as you want deep copies of A instances and exclusive ownership within B. Second, you indeed have to define a copy constructor for your class when you want it to be copyable. Same for an assignment operator. This is due to the fact that std::unique_ptr is a move-only type, which hinders the compiler to generate default implementations.
Other special member functions are not needed, though they might make sense. The compiler won't generate move constructor and move assignment operator for you (as you ship your own copy/assignment functions), though in your case, you can = default; them easily. The destructor can equally well be defined with = default;, which would be in line with the core guidelines.
Note that defining the destructor via = default should be done in a translation unit, as std::unique_ptr requires the full type do be known upon freeing its resource.
Whether you need a default constructor totally depends on how yo want to use the class B.
As #lubgr mentioned in his answer, You should return unique_ptr not a raw one from the clone function. Anyway, going to Your questions:
Do You need a copy constructor in B? Well it depends on Your use cases, but if You copy objects of class B You may need one. But as You said, You do it quite often, so it would be wise to consider more generic approach. One of these would be creating a wrapper for unique_ptr which would have copy constructor and which would make a deep copy of this pointer in this copy constructor.
Consider following example:
template<class T>
class unique_ptr_wrap {
public:
unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){}
unique_ptr_wrap(const unique_ptr_wrap &_wrap){
m_ptr = _wrap->clone();
}
unique_ptr_wrap(unique_ptr_wrap &&_wrap){
m_ptr = std::move(_wrap.m_ptr);
}
T *operator->() const {
return m_ptr.get();
}
T &operator*() const {
return *m_ptr;
}
private:
std::unique_ptr< T > m_ptr;
};
This again depends on Your needs. I personally would recommend overloading move constructor as well, to make it use less dynamic allocations (but this may be premateure optimization which is root of all evil).

C++ calls destructor immediately, even when rule of three is followed

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).

Best way to overload the C++ assignment operator

I have a class A which dynamically allocates memory for an integer(pointed by a class memeber say _pPtrMem) in its constructor and deallocates the same in destructor. To avoid Shallow copy, I have overloaded assignment operator and copy constructor. The widely used way in which assignment operator is overloaded is as following:
A& operator = (const A & iToAssign)
{
if (this == & iToAssign) // Check for self assignment
return *this;
int * pTemp = new int(*(iToAssign._pPtrMem)); // Allocate new memory with same value
if (pTemp)
{
delete _pPtrMem; // Delete the old memory
_pPtrMem = pTemp; // Assign the newly allocated memory
}
return *this; // Return the reference to object for chaining(a = b = c)
}
Another way for implementing the same could be
A& operator = (const A & iToAssign)
{
*_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values
return *this;
}
Since the second version is comparatively much simpler and faster(no deallocation, allocation of memory) why is it not used widely? Any problems that I am not able to make out?
Also we return an object of the same type from the assignment operator for chaining(a = b = c)... so instead of returning *this is it fine to return the iToAssign object as both objects are supposedly now equal?
Usually, the best way to implement a copy assignment operator is to provide a swap() function for your class (or use the standard one if it does what you want) and then implement the copy assignment operator via the copy constructor:
A& A::operator= (A iToAssign) // note pass by value here - will invoke copy constructor
{
iToAssign.swap(*this);
return *this;
}
// void swap(A& other) throws() // C++03
void A::swap(A& other) noexcept
{
std::swap(_pPtrMem, other._pPtrMem);
}
This makes sure that your copy assignment operator and copy constructor never diverge (that is, it cannot happen that you change one and forget to change the other).
No, there is no problem with your implementation. But having one integer dynamic allocated is at least very special.
This implementation is not widely used, because no one allocates a single integer on the free store. You usually use dynamic allocated memory for arrays with a variable length unknown at compile time. And in this case it's most of the time a good idea to just use std::vector.
No it's not fine, to return an different object. Identity is not the same as equality:
T a, b, d;
T& c = a = b;
c = d; // should change a, not b
Would you expect that the third line changes b?
Or a event better Example:
T a;
T& b = a = T();
This would result in a dangling reference, referencing an temporary and destructed object.
The first version is used in case _pPtrMem is a pointer to some basic type for instance a dynamically allocated array. In case the pointer is pointing to a single object with correctly implemented assignment operator the second version will do just as good. But in that case I don't think you will need to use a pointer at all.
In the second case, if _pPtrMem was initially unassigned, the line
*_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values
is causing an assignment to an invalid memory location (possibly a segmentation fault). This can only work if _pPtrMem has been allocated memory prior to this call.
In this case, the second implementation is by far the better.
But the usual reason for using dynamic in an object is because
the size may vary. (Another reason is because you want the
reference semantics of shallow copy.) In such cases, the
simplest solution is to use your first assignment (without the
test for self-assignment). Depending on the object, one might
consider reusing the memory already present if the new value
will fit; it adds to the complexity somewhat (since you have to
test whether it will fit, and still do the
allocation/copy/delete if it doesn't), but it can improve
performance in certain cases.

Does this C++ code leak memory?

struct Foo
{
Foo(int i)
{
ptr = new int(i);
}
~Foo()
{
delete ptr;
}
int* ptr;
};
int main()
{
{
Foo a(8);
Foo b(7);
a = b;
}
//Do other stuff
}
If I understand correctly, the compiler will automatically create an assignment operator member function for Foo. However, that just takes the value of ptr in b and puts it in a. The memory allocated by a originally seems lost. I could do a call a.~Foo(); before making the assignment, but I heard somewhere that you should rarely need to explicitly call a destructor. So let's say instead I write an assignment operator for Foo that deletes the int pointer of the left operand before assigning the r-value to the l-value. Like so:
Foo& operator=(const Foo& other)
{
//To handle self-assignment:
if (this != &other) {
delete this->ptr;
this->ptr = other.ptr;
}
return *this;
}
But if I do that, then when Foo a and Foo b go out of scope, don't both their destructors run, deleting the same pointer twice (since they both point to the same thing now)?
Edit:
If I understand Anders K correctly, this is the proper way to do it:
Foo& operator=(const Foo& other)
{
//To handle self-assignment:
if (this != &other) {
delete this->ptr;
//Clones the int
this->ptr = new int(*other.ptr);
}
return *this;
}
Now, a cloned the int that b pointed to, and sets its own pointer to it. Perhaps in this situation, the delete and new were not necessary because it just involves ints, but if the data member was not an int* but rather a Bar* or whatnot, a reallocation could be necessary.
Edit 2:
The best solution appears to be the copy-and-swap idiom.
Whether this leaks memory?
No it doesn't.
It seems most of the people have missed the point here. So here is a bit of clarification.
The initial response of "No it doesn't leak" in this answer was Incorrect but the solution that was and is suggested here is the only and the most appropriate solution to the problem.
The solution to your woes is:
Not use a pointer to integer member(int *) but to use just an integer (int), You don't really need dynamically allocated pointer member here. You can achieve the same functionality using an int as member.
Note that in C++ You should use new as little as possible.
If for some reason(which I can't see in the code sample) You can't do without dynamically allocated pointer member read on:
You need to follow the Rule of Three!
Why do you need to follow Rule of Three?
The Rule of Three states:
If your class needs either
a copy constructor,
an assignment operator,
or a destructor,
then it is likely to need all three of them.
Your class needs an explicit destructor of its own so it also needs an explicit copy constructor and copy assignment operator.
Since copy constructor and copy assignment operator for your class are implicit, they are implicitly public as well, Which means the class design allows to copy or assign objects of this class. The implicitly generated versions of these functions will only make a shallow copy of the dynamically allocated pointer member, this exposes your class to:
Memory Leaks &
Dangling pointers &
Potential Undefined Behavior of double deallocation
Which basically means you cannot make do with the implicitly generated versions, You need to provide your own overloaded versions and this is what Rule of Three says to begin with.
The explicitly provided overloads should make a deep copy of the allocated member and it thus prevents all your problems.
How to implement the Copy assignment operator correctly?
In this case the most efficient and optimized way of providing a copy assignment operator is by using:
copy-and-swap Idiom
#GManNickG's famous answer provides enough detail to explain the advantages it provides.
Suggestion:
Also, You are much better off using smart pointer as an class member rather than a raw pointer which burdens you with explicit memory management. A smart pointer will implicitly manage the memory for you. What kind of smart pointer to use depends on lifetime and ownership semantics intended for your member and you need to choose an appropriate smart pointer as per your requirement.
the normal way to handle this is to create a clone of the object the pointer points to, that is why it is important to have an assignment operator. when there is no assigment operator defined the default behavior is a memcpy which will cause a crash when both destructors try to delete the same object and a memory leak since the previous value ptr was pointing to in b will not be deleted.
Foo a
+-----+
a->ptr-> | |
+-----+
Foo b
+-----+
b->ptr-> | |
+-----+
a = b
+-----+
| |
+-----+
a->ptr
\ +-----+
b->ptr | |
+-----+
when a and b go out of scope delete will be called twice on the same object.
edit: as Benjamin/Als correctly pointed out the above is just referring to this particular example, see below in comments
The code as presented has Undefined Behavior. As such, if it leaks memory (as expected) then that is just one possible manifestation of the UB. It can also send an angry threatening letter to Barack Obama, or spew out red (or orange) nasal daemons, or do nothing, or act as if there was no memory leak, miraculously reclaiming the memory, or whatever.
Solution: instead of int*, use int, i.e.
struct Foo
{
Foo(int i): blah( i ) {}
int blah;
};
int main()
{
{
Foo a(8);
Foo b(7);
a = b;
}
//Do other stuff
}
That’s safer, shorter, far more efficient and far more clear.
No other solution presented for this question, beats the above on any objective measure.

How to pass parameters to a constructor?

I've got a class A, which consists of objects B and C. How to write a constructor of A that gets B and C objects? Should I pass them by value, by (const) reference, or a pointer? Where should I deallocate them?
I thought about pointers, because then I could write:
A a(new B(1,2,3,4,5), new C('x','y','z'))
But I don't know whether it's a good practice or not. Any suggestions?
Usually you pass by const reference:
A a(B(1,2,3,4,5), C('x','y','z'))
No need for pointers here.
Usually you store values unless copying is too inefficient.
The class definition then reads:
class A {
private:
B b;
C c;
public:
A(const B& b, const C& c): b(b), c(c) { }
};
Should I pass them by value, by (const) reference, or a pointer?
By const reference if object is big
by value if object is small
by const pointer if it is an optional argument that can be zero (i.e. "NULL")
by pointer if it is an optional argument that can be zero but will be owned (i.e. deallocated) by constructed class.
Please note that if your class have internal instances of B and C, then passing them by reference, value or const reference, will most likely involve using copy constructor or assignment operator. Which won't be necessary with pointers.
A a(new B(1,2,3,4,5), new C('x','y','z'))
Normally(i.e. not always) it is a bad idea, because:
if A doesn't deallocate arguments, you have a memory leak.
If A takes ownership of arguments and deallocates them, then you won't be able to pass values allocated on stack as arguments. Still, depending on your code design this may be acceptable (Qt 4 frequently takes ownership of objects created with new)
Where should I deallocate them?
The best idea is to make sure that compiler deallocates arguments automatically for you.
This means passing by reference, const reference or by value. Or using smart pointers.
What you pass in depends on your needs.
Do you need a copy of the thing you are passing in? Then pass by const-reference.
struct A
{
A(const B& b, const C& c) : m_b(b), m_c(c) {}
private:
B m_b;
C m_c;
};
And construct it like this:
A myA(B(1,2,3), C(4,5,6));
If you want your A object to refer to some other B and C objects (but not own them) then use pointers (or possibly references).
Edit: The examples given here do not respect the rule of the Big Three (thanks #Philipp!). If the definition of A is used as given below, the code will crash on copy construction for A, or on assignment for A. To define the code correctly, the assignment operator and copy constructor should be explicitly defined for A (or explicitly forbidden - declared as private and never implemented). (end Edit)
Should I pass them by value, by
(const) reference, or a pointer?
If A uses B and C, then hold them by reference or pointer inside of A. To choose between reference and pointer, see how B and C are allocated.
If they are local stack objects constructed in the same scope as A, then pass them by const reference.
If they are dynamically allocated objects that A uses, make A own them: pass them by pointers, and have A's destructor delete them.
If they are optional components of A, pass them by pointer (that can be null).
If A is not responsible of deleting them, pass them by * const.
Where should I deallocate them?
Usually where you no longer need them :).
If they are needed past the scope of A (if they are external objects that A uses) then delete them when A's scope is complete.
If they are owned by A, delete them in the destructor for A. It may make sense to also delete them during the lifetime of A, if the pointers should be changed.
Here's an example, where B is a replaceable component injected into A (and owned by A) and C is an optional component owned by A (but injected into A also).
("owned by" means A is responsible for deleting both objects)
class B;
class C;
class A
{
B* b;
C* c;
public:
A(B* const bb, C* const cc = 0) // cc is optional
: b(bb), c(cc)
{
}
void resetB(B* const bb = 0)
{
delete b;
b = bb;
}
~A()
{
resetB();
delete c;
}
};
{
A a(new B, new C);
a.resetB(); // delete B
a.resetB(new B); // delete former B and set a new one
} // both members of A are deleted
But I don't know whether it's a good
practice or not. Any suggestions?
It's up to you really, but you can write A a(B(1, 2, 4), C(1, 2, 3)) as easy as A a(new B(1, 2, 4), new C(1,2,3)); (in the former case - the one without new - the A::b and A::c should be references or objects/values inside the class, and A should not delete them at all).
The question should not be if you want to write the statement with dynamic allocation for B and C but if you need to. Dynamic allocation is slow and if you don't have a requirement for it you shouldn't do it.