Photo by Mathew Schwartz on Unsplash
Sparrow - C++ Type Checker
Define a better C++ copy/move semantics for your classes and structures
Let's start with a problem.
#include <iostream>
#include <utility>
struct Person {
Person(int a) : age(a) {}
int age = -1;
};
int main() {
Person p1(40);
Person p2 = std::move(p1);
std::cout << "Age of Person 1: " << p1.age << " years" << std::endl;
std::cout << "Age of Person 2: " << p2.age << " years" << std::endl;
}
What do you think is the output of the above program?
Oh, why is the age still showing 40 when we have moved the p1 using std::move(p1)
?
As the age
is an integer - a POD data type, the default move constructor can't change its value, leaving p1 in an undefined state post move! How do you handle this? By having a manually defined move constructor and resetting the age
to -1!
Now, let us look at the below code snippet -
#include <iostream>
#include <utility>
struct Person {
Person(int a) : age(a) {}
Person(Person&& rhs) {
age = std::move(rhs.age);
rhs.age = -1;
}
int age = -1;
};
int main() {
Person p1(40);
Person p2 = std::move(p1);
std::cout << "Age of Person 1: " << p1.age << " years" << std::endl;
std::cout << "Age of Person 2: " << p2.age << " years" << std::endl;
}
With this change, the output is now correct as -
We want to ensure the move/copy semantics are prescribed to such classes/structs! With this problem in hand, I wanted to design a type checker system around these trivial, default, or deleted move/copy semantics for C++ objects!
This is how the type checker library - sparrow - was born
https://github.com/vivekgalatage/sparrow.
With this library in place, you can enforce the classes to follow specific patterns with copy/move semantics. The above code will now become -
#include "sparrow.h"
struct Person {
Person(int a) : age(a) {}
Person(Person&& rhs) {
age = std::move(rhs.age);
rhs.age = -1;
}
int age = -1;
};
int main() {
using TypeChecker =
sparrow::TypeChecker<Person, sparrow::kCustomMoveConstructor>;
constexpr TypeChecker c1;
Person p1(42);
Person p2 = std::move(p1);
return 0;
}
Now, when the author tries to remove the manually defined move constructor, the compiler will throw an error as -
#include "sparrow.h"
struct Person {
Person(int a) : age(a) {}
// Missing the manually defined move constructor
int age = -1;
};
int main() {
using TypeChecker =
sparrow::TypeChecker<Person, sparrow::kCustomMoveConstructor>;
constexpr TypeChecker c1;
Person p1(42);
Person p2 = std::move(p1);
return 0;
}
=============================================
error: static_assert failed due to requirement 'custom_move_constructor()'
Do let me know your feedback on the GitHub repository URL via issues!
Happy coding!