Move semantics with non-pointer data members - c++

Probably this has been asked and answered already, but I don't know what to search for.
Can move semantics be used for non-pointer data members, if the data members have move assignment operators defined?
Suppose I have a class M that defines M::operator=(M&&) like this:
template <class T>
class M
{
public:
M()
{
mem_M = new T;
}
M& operator=(M&& src)
{
if (this != &src)
{
mem_M = src.mem_M;
src.mem_M = nullptr;
}
return *this;
}
private:
T* mem_M;
};
Now obviously I can have a class C<T> like this, with a move constructor that makes no use of T's move assignment operator:
template <class T>
class C
{
public:
C ()
{
mem_C = new T;
}
C (C&& rhs)
{
mem_C = rhs.mem_C;
rhs.mem_C = nullptr;
}
private:
T* mem_C;
};
However, what if I wanted C<T>::mem_C to not be a pointer but an ordinary member, how would I deal with C<T>::mem_C in the move-functions? I can of course invoke the move assignment operator T::operator=(T&&) to move the filed mem_C from one instance to the other, but how do I properly reset the instance of C passed to C<T>::C(C&&)?
This at least looks wrong to me:
template <class T>
class C
{
public:
C ()
{
mem_C = T();
}
C (C<T>&& rhs)
{
mem_C = std::move(rhs.mem_C);
rhs.mem_C = T(); // ?? like this?
}
private:
T mem_C;
};
So, what is the standard compliant way to reset non-pointer data members in move functions?

The move assignment/constructors for the contained types must leave the objects in an "acceptable" state, whatever that means for that type. Nothing outside the type being moved should have any responsibility for maintaining the state of the object.
Also, you want to make sure you're calling move constructors of contained types in your parent move constructor, not the contained type's move assignment as you are in your example:
// move constructor calls move constructor of contained elements
C (C<T>&& rhs) : mem_c(std::move(rhs.mem_c))
{
// anything in here is using already-constructed data members
}
// move assignment calls move assignment of contained elements
C & operator=(C<T>&& rhs) {
mem_c = std::move(rhs.mem_c);
}

Related

Why is the desctructor being invoked in this scenario?

In the following code , I am not able to understand why the destructor of the class Buf is invoked twice. When debugging I can see that it is being invoked the first time when the running thread is leaving the function Test::produce. The second time is when leaving the main function which essentially is when destructing the class EventQueue, something I would expect.
However, I dont understand why when leaving the function Test::produce the destructor of Buf is invoked. Specifically, I create the class Buf as a r-value passing it to the EventQueue and move to its internal cache. In fact, this has created me the problem that I end up trying ti free the same pointer twice which throws an exception.
template<typename T>
class EventQueue{
public:
void offer(T&& t) {
m_queue.try_emplace(std::this_thread::get_id()).first->second.push(std::move(t));
};
std::unordered_map<std::thread::id, std::queue<T>> m_queue;
};
class Buf{
const uint8_t *m_data;
const size_t m_size;
public:
Buf(const uint8_t *data, size_t size) : m_data(data), m_size(size) { }
size_t size() const { return m_size; }
const uint8_t *data() const { return m_data; }
~Buf()
{
std::cout << "dtor called " << std::endl;
free((void *)m_data);
}
};
class Test{ and was not expecting
public:
Test(shared_ptr<EventQueue<Buf>> buf) : m_buf(buf)
{
std::thread t1 = std::thread([this] { this->produce(10); });
t1.detach();
};
void produce(int msg_size) {
m_buf->offer(Buf(new uint8_t[msg_size], 10));
}
std::shared_ptr<EventQueue<Buf>> m_buf;
};
int main()
{
auto event_queue = std::make_shared<EventQueue<Buf>>();
Test tt(event_queue);
return 0;
}
The destructor is called two times because you have two objects to destroy. First - the temporary you created as an argument for the offer function parameter:
void produce(int msg_size) {
m_buf->offer(Buf(new uint8_t[msg_size], 10));
}
Second - when you add this temporary to std::queue container, it makes a copy under the hood:
void offer(T&& t) {
m_queue.try_emplace(std::this_thread::get_id()).first->second.push(std::move(t));
};
Every temporary object created must always be destructed. However the problem is not about how many objects were destructed, but that you ignore the rules of zero, three and five here. I.e. if you create any of a destructor, a copy constructor or a copy-assignment operator, you are supposed to take care of all three. Another side effect is that the compiler will not generate the move constructor and move assignment operator for you when any of the big three are explicitly defined. Thus, when passing rvalue-reference to a Buf constructor, you actually ends up with a copy constructor.
However even if it was a default move constructor, it would not solve your problem, because resources represented with raw pointers which your class instance "owns" (and is supposed to delete at some point) are not quite compatible with the implicit move constructor, which merely does member-wise std::move:
For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.
For any built-in types (including raw pointers), it means that nothing actually happens and they are just copied.
Long story short: you have to nullify the source object's member raw pointer explicitly:
Buf(Buf&& other) noexcept : m_data{ std::exchange(other.m_data, nullptr) }, m_size{ other.m_size } {}
The better solution would be to not mess with rules of three/five and stick to rule of zero, by leveraging RAII idiom and letting automatic storage duration to handle the resources without explicitly allocating/releasing them:
class Buf{
const std::vector<std::uint8_t> m_data;
public:
Buf(std::vector<std::uint8_t> data) : m_data{ std::move(data) } { }
const std::vector<std::uint8_t>& data() const {
return m_data;
}
};

How to suppress a member in implicit copy constructor/assignment operator?

I understand that the he implicit copy constructor/assignment operator does a member-wise copy of the source object.
Say my class has 1000 members. I want to suppress ONE of the member when doing assignment assignment(and the default value applies), the other 999 members still use the member-wise copy as the implicit assignment operator.
For example:
class Foo
{
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
Then we fill object f1 with some values:
Foo f1;
f1.s1 = "a";
f1.s2 = "b";
f1.s3 = "c";
...
Now we copy assign f1 (source) to f2 (target)
Foo f2 = f1;
How can I achieve the following result if I want to suppress "s2"?
assert(f2.s1 == "a");
assert(f2.s2 == ""); //default value
assert(f2.s3 == "c");
I understand that provide a copy constructor/assignment operator will solve this problem.
class Foo
{
Foo( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
};
Foo& Foo::operator=( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
return *this;
};
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
However, I have 1000 members. I don't want to implement such big functions.
If I implement function like this:
class Foo
{
Foo( const Foo& other)
{
*this = other;
s2 = "";
};
Foo& Foo::operator=( const Foo& other)
{
*this = other;
s2 = "";
return *this;
};
}
Obviously, that's endless recursive.
Here is the only choice for me at the moment, which is:
Foo f2 = f1;
f2.s2 = "";
However, suppose there are thousands of Foo f2 = f1; statements in my project. Finding them all to append one line after them is way too hard.
So, I want the minimum code change to customize the member-wise copy of an object. How can I do this?
I too agree with #gsamaras that you must remember the single responsibility principle. But unlike their answer, I think you can have your cake and eat it too.
Let's examine the responsibilities of your class. For one, it didn't care how all the data members were copied. That responsibility was delegated to the type that each member belonged to. We should maintain that, since this realization makes clear who should be responsible.
The data member in question, s2 is a std::string. That type copies itself. But what if we wrap it?
template<typename T>
class suppress_copies {
T _mem;
public:
// Allow changing the held member
operator T&() { return _mem; }
T& get() { return _mem; }
suppress_copies() = default;
// But stop automatic copies (potentially even handles moves)
suppress_copies(suppress_copies const&) {} // default initialize the member
suppress_copies& operator=(suppress_copies o) { // Accept default initialized "other"
using std::swap;
swap(_mem, o._mem);
return *this;
}
};
And that's pretty much it, this is the type that's responsible for suppressing the copy. Just designate the member with this wrapper:
suppress_copies<std::string> s2;
Have you heard about the Single responsibility principle? You are violating it with using too many data members for your class. Big functions and big classes are a nest for bugs, misunderstanding, and unwanted side effects. Just imagine the person that will maintain your code in the future..
As a result do not expect to get away with this that easily (I mean just a search and replace on your project is not that hard).
How to really cope with this problem?
Refactor!
Use composition with compact classes targetting only at what they have to really do.
Unfortunately, you can't invoke the compiler's default copy behavior for a class while also implementing custom copy behavior in the same class. If you perform custom copy construction/assignment, you will have to manually copy the 999 members while suppressing the 1 member.
You can implement the copy constructor in terms of the assignment operator, or vice versa, to avoid duplicating the copying code. For example:
class Foo {
...
public:
Foo(const Foo& other) :
s1(other.s1),
//s2(other.s2), //suppress s2
s3(other.s3),
...
s1000(other.s1000)
{
}
Foo& operator=(const Foo& other) {
if (&other != this) {
Foo(other).swap(*this);
}
return *this;
}
void swap(Foo &other) {
std::swap(s1, other.s1);
std::swap(s2, other.s2);
std::swap(s3, other.s3);
...
std::swap(s1000, other.s1000);
}
...
};
Yes, it is tedious work to setup (but then, so is having a class with 1000 data members to begin with. Consider refactoring the class into smaller pieces!). Once it is done, you don't have to worry about it anymore.
A simpler solution is to write a separate class just for s2 and disable its ability to copy its data. For example:
class string_nocopy {
std::string m_str;
public:
string_nocopy(const std::string &s = std::string()) : m_str(s) {}
string_nocopy(const string_nocopy &) : m_str() {}
string_nocopy& operator=(const std::string &s) {
m_str = s;
return *this;
}
string_nocopy& operator=(const string_nocopy &other) {
if (&other != this) m_str = "";
return *this;
}
operator std::string() { return m_str; }
...
};
Then you don't need a custom copy constructor or copy assignment operator in Foo, the defaults will suffice:
class Foo {
...
std::string s1;
string_nocopy s2;
std::string s3;
...
std::string s1000;
};
The most idiomatic way would be to have the members that need special processing know how to do it themselves (as in, embedded in their copy constructor), so to keep the copy constructor/assignment operator of aggregates always to the default. That's the idea behind having std::vector have its own copy constructor instead of having aggregates deal manually with each array they own.
This can work as long as the required behavior is general enough to stand on its own, and does not depend much from the rest of the aggregate; this is probably not your case - which poses the extra problems that (1) having an "autoreset" string (which only makes sense in the context of your class) as a member of your public interface is probably a bad idea, and (2) that inheriting from STL containers is problematic (although in this case it would work, since nobody would destroy it polymorphically).
So, for the cases where delegating to the member itself doesn't work, the only way out of this kind of problems (keep the default copy constructor/assignment operator but do some custom processing) that I found unfortunately is through an auxiliary struct. Put all the "normal" members into a FooAux structure with default copy constructor and assignment operator. Then Foo will inherit from this and add just the members that require special treatment; the copy constructor and assignment operator will delegate most of the work to the base class, adding just the custom processing for the extra members.
0. As it's been said by #gsamaras, you probably need to redisign you class.
But if for some reason currently this is not an option, well, there are some tricks possible.
If those members are all of the same type, then store them in a container (e.g. std::array) rather than in thousand members.
Otherwise, hide the members inside an inner private structure with default assignment. Then, in the outer class' operator=, first remember current value of the muted member, then assign the structure, then restore muted member to the previous value.
This is actually easier than you might imagine.
Declare a new string type, derived from std::string which has specialised copy behaviour. Then simply use the default copy/move behaviour in your outer class.
struct copyless_string : std::string
{
// delegte constructors to base class
using std::string::string;
// implement custom copy/assignment
copyless_string(copyless_string const& str)
: std::string()
{}
copyless_string& operator=(copyless_string const& str)
{
clear();
return *this;
}
// and default move behaviour
copyless_string(copyless_string && str) = default;
copyless_string& operator=(copyless_string && str) = default;
};
struct my_class
{
std::string s1, s2, s3, s4;
copyless_string s5; // <--- won't be copied
std::string s6, s7, s8, s9, s10;
};
Another way:
Defer the non-copy parts of the class to a base class and handle them separately.
Then use the rule of zero to avoid writing any general case copy behaviour at all.
#include <string>
#include <cassert>
struct CopylessFoo
{
CopylessFoo() : s2() {}
CopylessFoo(CopylessFoo const& other)
: CopylessFoo()
{}
CopylessFoo& operator=(CopylessFoo const& other)
{
s2.clear();
return *this;
}
CopylessFoo(CopylessFoo&& other) = default;
CopylessFoo& operator=(CopylessFoo&& other) = default;
std::string s2;
};
struct Foo : CopylessFoo
{
// rule of zero - no copy/assignment necessary
std::string s1;
// s2 provided by base class
std::string s3;
// ....
std::string s1000;
};
int main()
{
Foo f;
f.s1 = "Hello";
f.s2 = "world";
Foo f2 = f;
assert(f2.s1 == "Hello");
assert(f2.s2 == "");
}

Array initialization of objects without operator =, copy constructor or default constructor and run-time arguments

Disclaimer
I'm trying to allocate an array of objects that are neither copy constructible, assignable nor has a default constructor. The objects have arguments that are determined at run time. I know that you can solve this problem by having an array of pointers or cleverly using placement new but I'm more interested in if this is possible to do cleanly with C++11 (1y) magic. So please, this is purely of theoretical interest so avoid trying to solve "my problem" by offering a work around.
The code...
...So the question is: Is there a way to make the following work in C++11 or C++14:
class X{
public:
explicit X(int a){...}
X(const X&) = delete;
void operator = (const X&) = delete;
private:
...
};
class Y{
public:
Y(const std::vector<int>& args) {
x = new X[]{args};
}
~Y(){
delete [] x;
}
private:
X* x;
};
Criteria
Specifically I'm looking for a solution/construct that meets the following criteria:
X is not copy constructible.
X is not assignable.
X does not have a default no-argument constructor (construction has intended side-effects).
The arguments to X's constructor are not known until run time.
All instances of X must be laid out contiguously in memory.
X must be properly destructed when the array is deleted from it's base pointer (or if an intermediate class is used, when the intermediate object is destructed). This rules out array of pointers and naivë use of placement new.
Edit / Addendum
I forgot to mention that move constructor is not available. In the actual case at hand, X spawns a worker thread and is executing in the context of this of the initially constructed object, any attempt to use a move constructor will corrupt the state of the executing thread.
You can use std::vector and its emplace_back function if you make X at least movable.
class X{
public:
explicit X(int){}
X(X&&) = default;
X(const X&) = delete;
void operator = (const X&) = delete;
};
int main() {
std::vector<X> xs;
xs.emplace_back(0);
xs.emplace_back(1);
xs.emplace_back(2);
xs.emplace_back(3);
}
(If you declare a copy constructor, even if that declaration deletes it, the compiler will not automatically generate any special move member, so you need to explicitly request them)
This basically boils down to the "array with placement new" strategy, but all abstracted away into high-level notions.
If you cannot make use of a movable type, you have to implement a vector-like class that pre-allocates storage and never reallocates. There is nothing similar in the standard library.
You're going to have to keep track of the constructed elements by hand, but you can use allocator to help:
class Y{
public:
Y(const std::vector<int>& args):
alloc{},
n{args.size()},
x{alloc.allocate(n)}
{
auto end = x;
try {
for (auto arg: args)
alloc.construct(end++, arg);
} catch (...) {
while (end != x)
alloc.destroy(--end);
alloc.deallocate(x, n);
throw;
}
}
~Y() {
for (auto end = std::next(x, n); end != x; --end)
alloc.destroy(end);
alloc.deallocate(x, n);
}
private:
std::allocator<X> alloc;
const std::size_t n;
const X *x;
};
A class that is neither copyable nor movable, nor has a default constructor, cannot be held in a standard container (doesn't meet the requirements) or a variable-sized array allocation (which only allows argument specification for a fixed number of elements).
This means you need to allocate raw memory instead and use placement new to construct the objects. You can wrap this in a fixed-space vector class.
template <typename T>
class fixed_capacity_vector {
public:
using size_type = std::size_t;
fixed_capacity_vector(size_type capacity)
: data_(::operator new(capacity * sizeof(T)), size_(), capacity_(capacity)
{}
fixed_capacity_vector(const fixed_capacity_vector&) = delete;
fixed_capacity_vector(fixed_capacity_vector&&) = delete;
fixed_capacity_vector& operator =(const fixed_capacity_vector&) = delete;
fixed_capacity_vector& operator =(fixed_capacity_vector&&) = delete;
~fixed_capacity_vector() {
for (size_type i = 0; i < size_; ++i) data_[i].~T();
::operator delete(data_);
}
template <typename... Args>
T& emplace_back(Args&&... args) {
if (size_ == capacity_) throw out_of_range();
new (data_ + size_) T(std::forward<Args>(args)...);
++size_;
return data_[size_-1];
}
private:
T* data_;
size_type size_;
size_type capacity_;
};

C++11 Magically Deleted Constructor in BST

SOLVED! See below
So, I'm trying to learn C++11 by doing some simple data structures and playing around with them. I did something similar to the following BST example using raw pointers and new and delete and it worked fine. Then I wanted to do it in a way that was more leak-safe.
// tree.cpp
//
//
#include <iostream>
#include <memory>
/* DECLARATIONS */
template <typename T>
struct Tree {
// members
T data;
std::unique_ptr<Tree<T> > left;
std::unique_ptr<Tree<T> > right;
// methods
Tree (T arg);
~Tree () = default;
void insert (Tree<T> child);
void insert (T arg);
void print (void);
};
template <typename T>
Tree<T>::Tree (T arg) {
data = arg;
left = nullptr;
right = nullptr;
}
template <typename T>
void Tree<T>::insert (Tree<T> child) {
if (child.data < data) {
if (left) {
left->insert(child);
} else {
left = &child;
}
} else {
if (right) {
right->insert(child);
} else {
right = &child;
}
}
}
template <typename T>
void Tree<T>::insert (T arg) {
Tree<T> child (arg);
this->insert(child);
}
template <typename T>
void Tree<T>::print (void) {
if (left) {
left->print();
}
std::cout << data;
if (right) {
right->print();
}
}
int main (void) {
Tree<int> root (0);
root.insert(3);
root.insert(-3);
root.insert(-2);
root.insert(2);
root.insert(11);
root.print();
return 0;
}
I don't undersatnd the error I'm getting from clang++, however.
$ clang++ -std=c++11 tree.cpp
tree_new.cpp:50:16: error: call to deleted constructor of 'Tree<int>'
this->insert(child);
^~~~~
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert' requested here
root.insert(3);
^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
void insert (Tree<T> child);
^
tree_new.cpp:34:20: error: call to deleted constructor of 'Tree<int>'
left->insert(child);
^~~~~
tree_new.cpp:50:9: note: in instantiation of member function 'Tree<int>::insert'requested here
this->insert(child);
^
tree_new.cpp:66:8: note: in instantiation of member function 'Tree<int>::insert' requested here
root.insert(3);
^
tree_new.cpp:10:8: note: function has been explicitly marked deleted here
struct Tree {
^
tree_new.cpp:18:24: note: passing argument to parameter 'child' here
void insert (Tree<T> child);
^
2 errors generated.
Why does it say I explicitly deleted the constructor when I declared the struct? I even defined a constructor explicitly! Also, any comments on scoping/ownership failure would be appreciated. I'm pretty sure this won't work the way I did it anyways.
Solution
The following link from MSDN clarified how one can use unique_ptrs.
Special thanks to BatchyX for his initial explanation of the problem (using a unique_ptr as a member implicitly (though the compiler says "explicitly"...) deletes the copy constructor for the class), and for noting that indeed Tree is still movable.
Something mentioned in that MSDN article is that std::move() returns an rvalue of its argument.
Here is the suitably modified code (excluding the obviously modified declarations). Note that there might be some optimizations possible still by using std::forward, but this at least seems to compile and run correctly.
template <typename T>
void Tree<T>::insert (std::unique_ptr<Tree<T> >&& pchild) {
if (pchild->data < data) {
if (left) {
// recurse, but must match on the rvalue signature
left->insert(std::move(pchild));
} else {
// invokes the move constructor for left instead of its copy constructor
left = std::move(pchild);
}
} else {
if (right) {
right->insert(std::move(pchild));
} else {
right = std::move(pchild);
}
}
}
template <typename T>
void Tree<T>::insert (T arg) {
// what is inside the insert(...) is an rvalue.
this->insert(std::unique_ptr<Tree<T> >(new Tree<T> (arg)));
}
std::unique_ptr is not copyable, and any class that contains a unique_ptr is also not copyable, meaning struct Tree is not copyable. The argument to:
void Tree<T>::insert (Tree<T> child) {
is taking its argument by value. And:
template <typename T>
void Tree<T>::insert (T arg) {
Tree<T> child (arg);
this->insert(child);
}
requires the copy constructor. To correct this, make struct Tree moveable.
Note Tree is not moveable (in contrast to BatchyX's comment) due to the presence of:
~Tree () = default;
which is a user-declared destructor and from section 12.8 Copying and moving class objects (point 9) of the c++11 standard (draft n3337):
If the definition of a class X does not explicitly declare a move constructor,
one will be implicitly declared as defaulted if and only if
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
(I was uncertain about the implicit generation of the move members and asked this question to be certain). To make it moveable either:
remove the user-declared destructor, or
define a move constructor and move assignment operator
note: copy constructor of 'Tree' is implicitly deleted because field 'left' has a deleted copy constructor
std::unique_ptr doesn't have a copy-constructor
The compiler may not warn you on this (maybe you need to activate more warnings), but this will not work:
template <typename T>
void Tree<T>::insert (Tree<T> child) {
// ...
left = &child;;
}
This code takes the address of a temporary variable and stores it inside a unique_ptr. This is wrong. unique_ptr<A> is for storing pointers to objects that have been allocated with new. One of its purpose is to delete them on destruction so you don't have any memory leak.
Here, child is a temporary that will be destroyed when exiting the function. That mean left will contain a pointer pointing to whatever lies on the stack. This may lead to random corruptions, and ultimately crashes when your Tree object will be destroyed.
Even if child is a reference (rvalue or lvalue), you cannot assume that it has been allocated with new, because it may not be the case (In your code, it is never the case), and even if it is was, maybe the object is already managed elsewhere (e.g. in another unique_ptr) so you shouldn't mess with it.
What you want instead is to allocate memory for a Tree object and store it inside left:
left = new Tree<T>(child);
You still need to sort out the argument to insert which requires Tree to be copyable (hint: use a rvalue references instead: Tree<T>&& child), but this problem is even worse because your compiler cannot detect these kind of errors.
Your specialized constructor
Tree(T arg);
overrides the compiler-generated default-constructor. So you must include it on your own:
T() = default;

C++ : Implementing copy constructor and copy assignment operator

After reading about copy constructors and copy assignment operators in C++, I tried to create a simple example. Though the below snippet apparently works, I am not sure whether I am implementing the copy constructor and copy assignment operator the right way. Could you please point out if there are any mistakes/improvements or a better example to understand the relevant concepts.
class Foobase
{
int bInt;
public:
Foobase() {}
Foobase(int b) { bInt = b;}
int GetValue() { return bInt;}
int SetValue(const int& val) { bInt = val; }
};
class Foobar
{
int var;
Foobase *base;
public:
Foobar(){}
Foobar(int v)
{
var = v;
base = new Foobase(v * -1);
}
//Copy constructor
Foobar(const Foobar& foo)
{
var = foo.var;
base = new Foobase(foo.GetBaseValue());
}
//Copy assignemnt operator
Foobar& operator= (const Foobar& other)
{
if (this != &other) // prevent self-assignment
{
var = other.var;
base = new Foobase(other.GetBaseValue());
}
return *this;
}
~Foobar()
{
delete base;
}
void SetValue(int val)
{
var = val;
}
void SetBaseValue(const int& val)
{
base->SetValue(val);
}
int GetBaseValue() const
{
return(base->GetValue());
}
void Print()
{
cout<<"Foobar Value: "<<var<<endl;
cout<<"Foobase Value: "<<base->GetValue()<<endl;
}
};
int main()
{
Foobar f(10);
Foobar g(f); //calls copy constructor
Foobar h = f; //calls copy constructor
Foobar i;
i = f;
f.SetBaseValue(12);
f.SetValue(2);
Foobar j = f = z; //copy constructor for j but assignment operator for f
z.SetBaseValue(777);
z.SetValue(77);
return 1;
}
Your copy assignment operator is implemented incorrectly. The object being assigned to leaks the object its base points to.
Your default constructor is also incorrect: it leaves both base and var uninitialized, so there is no way to know whether either is valid and in the destructor, when you call delete base;, Bad Things Happen.
The easiest way to implement the copy constructor and copy assignment operator and to know that you have done so correctly is to use the Copy-and-Swap idiom.
Only Foobar needs a custom copy constructor, assignment operator and destructor. Foobase doesn't need one because the default behaviour the compiler gives is good enough.
In the case of Foobar you have a leak in the assignment operator. You can easily fix it by freeing the object before allocating it, and that should be good enough. But if you ever add a second pointer member to Foobar you will see that that's when things get complicated. Now, if you have an exception while allocating the second pointer you need to clean up properly the first pointer you allocated, to avoid corruption or leaks. And things get more complicated than that in a polynomial manner as you add more pointer members.
Instead, what you want to do is implement the assignment operator in terms of the copy constructor. Then, you should implement the copy-constructor in terms of a non-throwing swap function. Read about the Copy & Swap idiom for details.
Also, the default constructor of Foobar doesn't default-initialize the members. That's bad, because it's not what the user would expect. The member pointer points at an arbitrary address and the int has an arbitrary value. Now if you use the object the constructor created you are very near Undefined Behaviour Land.
I have a very simple patch for you:
class Foobar
{
int var;
std::unique_ptr<FooBase> base;
...
That should get you started.
The bottom line is:
Don't call delete in your code (Experts see point 2)
Don't call delete in your code (you know better...)