Rule Of Five – C++

Hello and Welcome to my blog!

To keep my skills sharp while I am looking for work, I have been reviewing what I have learned at college.

Today I reviewed the Rule of Five in C++. The rule of five is the programming pattern that states when a class implements any of the following functions, it must implement all of them. A rule of three exist as well, the rule of five is an expanded version.

The Five functions in the rule of five are…

1 – Copy Assignment Operator
2 – Copy Constructor
3 – Deconstructor
4 – Move Assignment Operator
5 – Move Constructor

I decided to Implement the rule of five two ways, first as a Templated class and second as a Non-Templated class.

This code was good practice, and I am planning on releasing more blogs like this one soon. All the code is below, thanks for reading my blog.

Templated Rule Of Five

template < class T >
  class RuleOfFiveTemplated {
    size_t size = 0;
    T * data = nullptr;
    public:
      // Default Constructor
      RuleOfFiveTemplated() {
        std::cout << (void * ) this << ": RuleOfFiveTemplated constructor()\n";
      }

    // Constructor Overload
    RuleOfFiveTemplated(size_t size): size(size), data(new T[size]) {
      cout << (void * ) this << ": RuleOfFiveTemplated (" << size << ") constructor\n";
    }

    // One - Assignment Operator
    RuleOfFiveTemplated & operator = (const RuleOfFiveTemplated & rhs) {
      cout << (void * ) this << ": RuleOfFiveTemplated assignment operator, size = " << size << ", rhs.size = " << rhs.size << endl;
      if (this != & rhs) {
        delete[] data;
        data = nullptr;
        size = 0;

        if (rhs.data) {
          size = rhs.size;
          try {
            data = new T[size];
            memcpy(data, rhs.data, size * sizeof(T));
          } catch (const std::bad_alloc & err) {
            cout << (void * ) this << ": RuleOfFiveTemplated Failed to copy value inside data: " << err.what() << endl;
          }
        }
      } else {
        cout << (void * ) this << ": RuleOfFiveTemplated copy assignment operator called on itself" << endl;
      }
      return *this;
    }

    // Two - Copy Constructor
    RuleOfFiveTemplated(const RuleOfFiveTemplated & rhs) {
      cout << (void * ) this << ": RuleOfFiveTemplated copy constructor, size = " << size << ", rhs.size = " << rhs.size << endl;
      data = nullptr;
      * this = rhs;
    }

    // three - Move Assignment Operator
    RuleOfFiveTemplated && operator = (RuleOfFiveTemplated && rhs) noexcept {
      cout << (void * ) this << ": RuleOfFiveTemplated move assignment operator, size = " << size << ", rhs.size = " << rhs.size << endl;
      if (this != & rhs) {
        delete[] data;

        size = rhs.size;
        data = rhs.data;

        rhs.size = 0;
        rhs.data = nullptr;
      } else {
        cout << (void * ) this << ": RuleOfFiveTemplated move assignment operator called on itself\n";
      }
      return std::move( * this);
    }

    // Four - Move Constructor
    RuleOfFiveTemplated(RuleOfFiveTemplated && rhs) noexcept {
        cout << (void * ) this << ": RuleOfFiveTemplated move constructor, size = " << size << ", rhs.size = " << rhs.size << endl;
        data = nullptr;
        * this = std::move(rhs);
      }

      // Five - De-Constructor
      ~RuleOfFiveTemplated() {
        cout << (void * ) this << ": RuleOfFiveTemplated destructor, size=" << size << "\n";
        delete[] data;
      }

    // Print
    void print() {
      cout << (void * ) this << ": size=" << size << " (" << size * sizeof(T) << " BYTES)\n";
    }
  };

Non-Templated Rule Of Five

class RuleOfFive {
	size_t size = 0;
	double* data = nullptr;
public:
	RuleOfFive() {
		cout << (void*)this << ": RuleOfFive default constructor" << endl;
	}

	RuleOfFive(double size) : size(size), data(new double[size]) {
		cout << (void*)this << ": RuleOfFive constructor overload." << endl;
	}

	// One - Copy assignment operator
	RuleOfFive& operator=(RuleOfFive& rhs) {
		cout << (void*)this << ": RuleOfFive copy assignment operator, size = " << size << ", rhs.size = " << rhs.size << endl;
		if (this != &rhs) {
			delete[] data;
			data = nullptr;
			size = 0;

			if (rhs.data) {
				size = rhs.size;
				try
				{
					data = new double[size];
					memcpy(data, rhs.data, size * sizeof(double));
				}
				catch (const std::bad_alloc&)
				{
					cout << (void*)this << ": RuleOfFive Failed to copy value inside data" << endl;
				}
			}
		}
		else {
			cout << (void*)this << ": RuleOfFive copy assignment operator called on itself" << endl;
		}

		return *this;
	}

	// Two - Copy Constructor
	RuleOfFive(RuleOfFive& rhs) {
		cout << (void*)this << ": RuleOfFive copy constructor, size = " << size << ", rhs.size = " << rhs.size << endl;
		data = nullptr;
		*this = rhs;
	}

	// Three - Move Assignment operator
	RuleOfFive&& operator=(RuleOfFive&& rhs) noexcept {
		cout << (void*)this << ": RuleOfFive move assignment operator, size = " << size << ", rhs.size = " << rhs.size << endl;
		if (this != &rhs) {
			delete[] data;

			size = rhs.size;
			data = rhs.data;

			rhs.size = 0;
			rhs.data = nullptr;
		}
		else {
			cout << (void*)this << ": RuleOfFive move assignment operator called on itself" << endl;
		}

		return std::move(*this);
	}

	// Four - Move constructor
	RuleOfFive(RuleOfFive&& rhs) noexcept {
		cout << (void*)this << ": RuleOfFive move constructor, size = " << size << ", rhs.size = " << rhs.size << endl;
		data = nullptr;
		*this = std::move(rhs);
	}

	// Five - Deconstuctor
	~RuleOfFive() {
		cout << (void*)this << ": RuleOfFive deconstuctor" << endl;
	}

	// Print
	void print()
	{
		cout << (void*)this << ": size=" << size << " (" << size * sizeof(double) << " BYTES)" << endl;
	}
};

Main Function

#include <iostream>
#include <cstring> 
using namespace std;

int main(int argc, char** argv)
{
	cout << "Rule Of Five" << endl << endl;

	// Test Default Constructors
	cout << endl << "Testing Default Constructor" << endl << "=========================================" << endl;

	RuleOfFive x; 
	cout << "x created : ";
	x.print();
	
	RuleOfFiveTemplated<double> tx;
	cout << "tx created : ";
	tx.print();

	// Test Constructor Overloads
	cout << endl << "Testing Constructor Overloads" << endl << "=========================================" << endl;

	RuleOfFive y(1000);
	cout << "y created : ";
	y.print();

	RuleOfFiveTemplated<double> ty(1000);
	cout << "ty created : ";
	ty.print();

	// Test Copy Assignment operator
	cout << endl << "Test Rule One - Copy Assignment operator" << endl << "=========================================" << endl;

	x = y;
	cout << "x : lhs : ";
	x.print();
	cout << "y : rhs : ";
	y.print();

	tx = ty;
	cout << "tx : lhs : ";
	tx.print();
	cout << "ty : rhs : ";
	ty.print();

	// Test Copy Constructor
	cout << endl << "Test Rule Two - Copy Constructor" << endl << "=========================================" << endl;

	RuleOfFive z(x);
	cout << "z created : lhs : ";
	z.print();
	cout << "x : rhs : ";
	x.print();

	RuleOfFiveTemplated<double> tz(tx);
	cout << "tz created : lhs : ";
	tz.print();
	cout << "tx : rhs : ";
	tx.print();

	// Test Move Assignment operator
	cout << endl << "Test Rule Three - Move Assignment operator" << endl << "=========================================" << endl;

	y = std::move(x);
	cout << "y : lhs : ";
	y.print();
	cout << "x : rhs : ";
	x.print();

	ty = std::move(tx);
	cout << "ty : lhs : ";
	ty.print();
	cout << "tx : rhs : ";
	tx.print();

	// Test Move Constructor
	cout << endl << "Test Rule Four - Move Constructor" << endl << "=========================================" << endl;

	RuleOfFive a(std::move(y));
	cout << "a created : lhs : ";
	a.print();
	cout << "y : rhs : ";
	y.print();

	RuleOfFiveTemplated<double> ta(std::move(ty));
	cout << "ta created : lhs : ";
	ta.print();
	cout << "ty : rhs : ";
	ty.print();

	// Test Deconstructors
	cout << endl << "Test Rule Five - Deconstructors" << endl << "=========================================" << endl;
}

	

Reversing Words Order in C++ and Using CMake

Saw this challenge in a job posting, thought I would give it a try. I also set up CMake for the first time to build this project. It worked great. I was able to create the program on my windows machine using the command line as I wanted. I think I like Linux Make a bit better though. I think its a bit simpler. I don’t have a Linux machine set up at the moment, so I am glad I got CMake working.

Challenge: Reversing Words Order

This is a pretty simple challenge. The challenge is to write a program that can take words like this “Keyboard and Mouse” and change it to “Mouse and Keyboard” as the output.

My Code:

#include <iostream>
using namespace std;

char *reverseWordOrder(char *, int);

int main()
{
    const int size = 19;
    char wordsToReverse[size] = "Keyboard and Mouse";
    cout << reverseWordOrder(wordsToReverse, size) << endl;
    return 0;
}

char *reverseWordOrder(char *words, int size)
{
    char *reversedWords = new char[size];
    int cursor = 0;

    for (int i = size; i >= 0; i--)
    {
        if (words[i] == ' ' || i == 0)
        {
            int j = (i == 0) ? i : i + 1;

            while (words[j] != ' ' && words[j] != '\0')
            {
                reversedWords[cursor] = words[j];
                cursor++;
                j++;
            }

            if (cursor < size - 1)
            {
                reversedWords[cursor] = ' ';
                cursor++;
            }
            reversedWords[cursor] = '\0';
        }
    }

    return reversedWords;
} 

Conclusion:

I looked up a solution online after I finished mine. Performance-wise I believe mine would be faster. I choose to navigate backwards through the phrase and grab each word then add it to a new string.

Example: (Note: This example is not exactly what the code is doing)
Input: Keyboard and Mouse
Step1: Get the last word.
Output: Mouse
Step2: Get the next word.
Output: Mouse and
Step3: Get the next word.
Output: Mouse and Keyboard

In the solution I found online here, they reversed each word individually and then reversed the whole phrase. The act of reversing the words and phrase is a smart way of completing the task, but it is more expensive. In this algorithm, it will visit each letter around four times. In my algorithm, it visits each letter two times.

Example: (Note: This example is not exactly what the code is doing)
Input: Keyboard and Mouse
Step1: Reverse each word.
Output: draobyeK dna esuoM
Step2: Reversed the whole phrase.
Output: Mouse and Keyboard