Created
July 6, 2023 20:23
-
-
Save SteelPh0enix/11a054db32d257072b7ddfc69ed930bf to your computer and use it in GitHub Desktop.
Rule of Five
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
template <typename T> | |
class Container { | |
public: | |
// Prevents creating nameless objects without value - assume that these are invalid. | |
Container() = delete; | |
Container(T const value, std::string const& name) : m_name { name } | |
{ | |
create_value(value); | |
std::cout << "Value c-tor called, created object '" << this->name() << "' with value '" | |
<< this->value() << "'\n"; | |
} | |
Container(Container const& other) : m_name { other.m_name } | |
{ | |
create_value(*other.m_value); | |
std::cout << "Copy c-tor called, copied object '" << name() << "' with value '" << value() | |
<< "'\n"; | |
} | |
Container(Container&& other) : m_value { other.m_value }, m_name { std::move(other.m_name) } | |
{ | |
std::cout << "Move c-tor called, moved object '" << name() << "' with value '" << value() | |
<< "'\n"; | |
// Invalidate members of moved instance to preserve object cohesion | |
// `name` has already been invalidated by std::string's move c-tor | |
other.m_value = nullptr; | |
} | |
Container& operator=(Container const& other) | |
{ | |
m_name = other.m_name; | |
// Assume pessimistic scenario - previous data must be destroyed, cannot be reassigned | |
destroy_value(); | |
create_value(*other.m_value); | |
std::cout << "Copy operator called, copied object '" << name() << "' with value '" | |
<< value() << "'\n"; | |
return *this; | |
} | |
Container& operator=(Container&& other) | |
{ | |
m_name = std::move(other.m_name); | |
m_value = other.m_value; | |
// Invalidate members of moved instance to preserve object cohesion | |
// `name` has already been invalidated by std::string's move c-tor | |
other.m_value = nullptr; | |
std::cout << "Move operator called, moved object '" << name() << "' with value '" << value() | |
<< "'\n"; | |
return *this; | |
} | |
~Container() | |
{ | |
if (is_valid()) { | |
std::cout << "Destructor called, destroying object '" << name() << "' with value '" | |
<< value() << "'\n"; | |
destroy_value(); | |
} else | |
std::cout << "Destructor called, destroying invalid object (no dealloc performed)\n"; | |
} | |
std::string const& name() const | |
{ | |
return m_name; | |
} | |
T const& value() const | |
{ | |
return *m_value; | |
} | |
bool is_valid() const | |
{ | |
return m_value != nullptr; | |
} | |
std::string to_string() const | |
{ | |
if (is_valid()) | |
return name() + std::string(" contains ") + std::to_string(value()); | |
return "Invalid object!"; | |
} | |
private: | |
T* m_value { nullptr }; | |
std::string m_name {}; | |
static inline size_t m_allocations { 0u }; | |
static inline size_t m_deallocations { 0u }; | |
void create_value(T const new_value) | |
{ | |
m_value = new T { new_value }; | |
m_allocations++; | |
std::cout << "Value allocated, performed " << m_allocations << " allocations\n"; | |
} | |
void destroy_value() | |
{ | |
delete m_value; | |
m_deallocations++; | |
std::cout << "Value deallocated, performed: " << m_deallocations << " deallocations\n"; | |
} | |
}; | |
int main() | |
{ | |
std::cout << "=== Creating 'a' ===\n"; | |
auto const a = Container(42, "First"); | |
std::cout << "a = " << a.to_string() << '\n'; | |
std::cout << "\n=== Creating 'b' ===\n"; | |
auto b = Container(69, "Second"); | |
std::cout << "b = " << b.to_string() << '\n'; | |
std::cout << "\n=== Creating 'c' by copying 'a' ===\n"; | |
auto c = a; | |
std::cout << "a = " << a.to_string() << '\n'; | |
std::cout << "c = " << c.to_string() << '\n'; | |
std::cout << "\n=== Creating 'd' by moving 'b' ===\n"; | |
auto d = std::move(b); | |
std::cout << "b = " << b.to_string() << '\n'; | |
std::cout << "d = " << d.to_string() << '\n'; | |
std::cout << "\n=== Final state of all objects ===\n"; | |
std::cout << "a = " << a.to_string() << '\n'; | |
std::cout << "b = " << b.to_string() << '\n'; | |
std::cout << "c = " << c.to_string() << '\n'; | |
std::cout << "d = " << d.to_string() << '\n'; | |
std::cout << "\n=== End of main ===\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment