Move/Copy Constructors

This page describes how to implement C++11 move and copy constructors in classes.

In the API there are strict requirements as to how classes need to be implemented, so that they can function e.g. with sort and array templates.

Type I

The first distinction is whether your class is a POD (plain old data) class or not.

POD classes can be copied as a whole by a simple MemCopy() and do not allocate any memory. POD classes do not require any special move/copy constructors.

Example:

class Vector
{
public:
};

The arrays use type traits to automatically determine whether objects can be moved or copied with memmove()/memcpy(). To force a specific

Note
For arrays and sorting you don't need to specify any special flags, but you can make use of BASEARRAYFLAGS::MOVEANDCOPYOBJECTS and BASESORTFLAGS::MOVEANDCOPYOBJECTS to increase copy & move speed.


Type II

For all other classes the first step is to use of the MAXON_DISALLOW_COPY_AND_ASSIGN macro at the beginning of the class. It declares the class copy constructor and operator private (not all compilers support C++11 deleted functions yet) and prevents copy and assign operations which implicitely expect success (or throw an exception).

Example:

class MemoryBlock
{
private:
void* _memory;
Int _memorySize;
};

To use such a class in combination with (most types of) arrays we need to define a move constructor and move assignment operator. Move constructors and operators define how to move the class in memory efficiently, without the need to copy the class and its contents.

Example:

class Example1
{
public:
Example1() {}
~Example1() {}
Example1(Example1&& src) : _data(std::move(src._data)) {}
private:
BaseArray<Char> _data;
};

The statement MAXON_OPERATOR_MOVE_ASSIGNMENT(className) automatically defines the move assignment operator based on the move constructor, so we don't have to write the same code twice.

After defining the move constructor arrays or sorts can be used (otherwise you'd get a compile error in one of the header files):

BaseArray<Example1> test;
Example1* ptr = test.Append();

For derived classes the code is slightly more difficult to write:

class Example2 : public Example1
{
public:
Example2() {}
Example2(Example2&& src) : Example1(std::move(src)), _val2(std::move(src._val2))
{
src._val2 = 0;
}
private:
Int _val2 = 1;
};


Type III

If your class does not only need to be moved in memory, but also needs to be copied or duplicated the member CopyFrom() needs to be added:

class Example1
{
public:
Example1() {}
~Example1() {}
Example1(Example1&& src) : _data(std::move(src._data)) {}
MAXON_WARN_UNUSED Result<void> CopyFrom(const Example1& src)
{
if (_data.CopyFrom(src._data) == maxon::FAILED)
return OutOfMemoryError(CREATE);
return OK;
}
private:
BaseArray<Char> _data;
};

Defining CopyFrom() is the only clean way to deal with out of memory situations, which cannot properly be tracked by using regular C++ copy constructors/operators without using exceptions.

After defining a CopyFrom() method you're now able to copy arrays:

BaseArray<Example1> test, test2;
if (test.CopyFrom(test2) == maxon::FAILED)
return false;

or append data by copying it (though this is not the most efficient way to do):

BaseArray<Example1> test;
Example1 val;
if (test.Append(val) == nullptr)
return false;