diff options
Diffstat (limited to 'graphs/cpp/smtptr')
| -rw-r--r-- | graphs/cpp/smtptr/main.cc | 20 | ||||
| -rw-r--r-- | graphs/cpp/smtptr/shared_pointer.hh | 166 | ||||
| -rw-r--r-- | graphs/cpp/smtptr/shared_pointer.hxx | 144 | ||||
| -rw-r--r-- | graphs/cpp/smtptr/shared_pointer_is_a.cc | 47 |
4 files changed, 377 insertions, 0 deletions
diff --git a/graphs/cpp/smtptr/main.cc b/graphs/cpp/smtptr/main.cc new file mode 100644 index 0000000..a574d45 --- /dev/null +++ b/graphs/cpp/smtptr/main.cc @@ -0,0 +1,20 @@ +#include "shared_pointer.hh" + +int main() +{ + // Lifetime of the data + { + SharedPointer<int> p2; + { + SharedPointer<int> p1{ new int{ 5 } }; + p2 = p1; // Now both SharedPointers own the memory + } + // p1 is freed, but the int pointer remains + // Memory still exists, due to p2 + std::cout << "Value of p2: " << *p2 << std::endl; // Output: 5 + } + // p2 is freed, and since no one else owns the memory, + // the int pointer is freed too + + return 0; +} diff --git a/graphs/cpp/smtptr/shared_pointer.hh b/graphs/cpp/smtptr/shared_pointer.hh new file mode 100644 index 0000000..cc24243 --- /dev/null +++ b/graphs/cpp/smtptr/shared_pointer.hh @@ -0,0 +1,166 @@ +#pragma once + +#include <cassert> +#include <iostream> +#include <string> + +template <typename T> +class SharedPointer +{ +public: + // The type pointed to. + using element_type = T; + + /** + ** \brief Construct a counted reference to a newly allocated object. + */ + SharedPointer(element_type* p = nullptr); + + /** + ** \brief Destroy the SharedPointer. + ** The object pointed to is destroyed only if it is not referenced anymore. + ** Take care to free everything ... + */ + ~SharedPointer(); + + /** + ** \brief Copy constructor. + ** \return A new SharedPointer, pointing + ** to the underlying data of \a other. + ** + ** Although the implementation is subsumed by the previous, more + ** generic one, the C++ standard still mandates this specific + ** signature. Otherwise, the compiler will provide a default + ** implementation, which is of course wrong. Note that the + ** same applies for the assignment operator. + */ + SharedPointer(const SharedPointer<element_type>& other); + + /// \name Assignments. + /// \{ + + /** + ** \brief Replace the underlying data with \a p + ** A call to \c reset is strictly equivalent to: + ** \code + ** r = SharedPointer<element_type>(p); + ** \endcode + ** This line implicitly calls the destructor of \a r before assigning + ** it a new value. + ** \warning You can't reset your \c SharedPointer with the + ** same pointer as the current one. In this case, nothing should + ** be done. + ** \warning Be mindful of other \c SharedPointers + ** which could also be pointing to the same data. + */ + void reset(element_type* p); + + /** + ** \brief Reference assignment + ** Its behavior is similar to \c reset() but you + ** have to use the existing SharedPointer \a other + ** instead of creating a new instance. + */ + SharedPointer<element_type>& + operator=(const SharedPointer<element_type>& other); + /// \} + + /// \name Access to data. + /// \{ + + // Access via a reference. + element_type& operator*() const; + // Access via a pointer. + element_type* operator->() const; + + // Returns the underlying data pointer. + element_type* get() const; + + // Returns the number of SharedPointer objects referring to the same managed + // object + long use_count() const; + /// \} + + /// \name Equality operators. + /// \{ + + /** + ** \brief Reference comparison. + ** Returns true if the two references point to the same object. + */ + template <typename U> + bool operator==(const SharedPointer<U>& rhs) const; + + /** + ** \brief Reference comparison. + ** Returns false if the two references point to the same object. + */ + template <typename U> + bool operator!=(const SharedPointer<U>& rhs) const; + + /** + ** \brief Reference comparison. + ** Returns true if this points to \a p. + */ + bool operator==(const element_type* p) const; + + /** + ** \brief Reference comparison. + ** Returns false if this points to \a p. + */ + bool operator!=(const element_type* p) const; + + /** + ** \brief Move assignment operator for SharedPointer. + ** + ** This operator transfers ownership of the managed object from the + ** \a other to this SharePointer. + ** After the assignment, the \a other will be empty. + ** \warning Don't forget to update the reference counter. + ** + ** Returns a reference to this SharedPointer. + */ + SharedPointer<element_type>& operator=(SharedPointer&& other) noexcept; + + /** + ** \brief Move constructor for SharedPointer. + ** + ** This constructor transfers ownership of the managed object from \a other + ** SharedPointer to the newly created SharedPointer. + ** + */ + SharedPointer(SharedPointer&& other); + + /// \} + + /** + ** \brief Test for validity + ** Returns true if the reference is valid, i.e. it points to an object. + ** This conversion operator allows users to write: + ** + ** \code + ** SharedPointer<int> p1; + ** if (p1) // Here false + ** ... + ** \endcode + */ + operator bool() const; + + /** + ** \brief Test fellowship. + ** Returns true if the SharedPointer points to an object which + ** is of the specified type. + ** Look at the given example file shared_pointer_is_a.cc + ** to better understand its purpose. + */ + template <typename U> + bool is_a() const; + +private: + // Pointer to the underlying data. + element_type* data_; + // A counter shared between all ref pointers to \a data_. + long* count_; +}; + +#include "shared_pointer.hxx" diff --git a/graphs/cpp/smtptr/shared_pointer.hxx b/graphs/cpp/smtptr/shared_pointer.hxx new file mode 100644 index 0000000..fbc0792 --- /dev/null +++ b/graphs/cpp/smtptr/shared_pointer.hxx @@ -0,0 +1,144 @@ +#pragma once +#include "shared_pointer.hh" +template <typename T> +SharedPointer<T>::SharedPointer(element_type* p) +{ + if (p == nullptr) + { + data_ = nullptr; + count_ = nullptr; + } + else + { + data_ = p; + count_ = new long{ 1 }; + } +} +template <typename T> +SharedPointer<T>::~SharedPointer() +{ + if (count_ != nullptr) + { + (*count_)--; + if (*count_ == 0) + { + delete count_; + if (data_ != nullptr) + delete data_; + } + } +} +template <typename T> +SharedPointer<T>::SharedPointer(const SharedPointer<element_type>& other) +{ + this->~SharedPointer(); + data_ = other.data_; + if (data_ == nullptr) + count_ = nullptr; + count_ = other.count_; + if (count_ != nullptr) + (*count_)++; +} +template <typename T> +void SharedPointer<T>::reset(element_type* p) +{ + if (data_ == p) + return; + this->~SharedPointer(); + data_ = p; + if (p == nullptr) + count_ = nullptr; + else + count_ = new long{ 1 }; +} +template <typename T> +SharedPointer<T>& SharedPointer<T>::operator=(const SharedPointer<T>& other) +{ + this->~SharedPointer(); + + data_ = other.data_; + count_ = other.count_; + if (nullptr != other.data_) + { + (*this->count_)++; + } + return *this; +} +template <typename T> +T& SharedPointer<T>::operator*() const +{ + return *data_; +} + +template <typename T> +T* SharedPointer<T>::operator->() const +{ + return data_; +} +template <typename T> +T* SharedPointer<T>::get() const +{ + return data_; +} +template <typename T> +long SharedPointer<T>::use_count() const +{ + if (count_ == nullptr) + return 0; + return *count_; +} +template <typename T> +template <typename U> +bool SharedPointer<T>::operator==(const SharedPointer<U>& rhs) const +{ + if (rhs.data_ == this->data_) + return true; + return false; +} +template <typename T> +template <typename U> +bool SharedPointer<T>::operator!=(const SharedPointer<U>& rhs) const +{ + return !(*this == rhs); +} +template <typename T> +bool SharedPointer<T>::operator==(const T* p) const +{ + return this->data_ == p; +} +template <typename T> +bool SharedPointer<T>::operator!=(const T* p) const +{ + return this->data_ != p; +} +template <typename T> +SharedPointer<T>& SharedPointer<T>::operator=(SharedPointer<T>&& other) noexcept +{ + this->~SharedPointer(); + data_ = other.data_; + count_ = other.count_; + other.data_ = nullptr; + other.count_ = nullptr; + return *this; +} +template <typename T> +SharedPointer<T>::SharedPointer(SharedPointer&& other) +{ + this->~SharedPointer(); + data_ = other.data_; + count_ = other.count_; + + other.data_ = nullptr; + other.count_ = nullptr; +} +template <typename T> +SharedPointer<T>::operator bool() const +{ + return data_ != nullptr; +} +template <typename T> +template <typename U> +bool SharedPointer<T>::is_a() const +{ + return dynamic_cast<U*>(data_); +}
\ No newline at end of file diff --git a/graphs/cpp/smtptr/shared_pointer_is_a.cc b/graphs/cpp/smtptr/shared_pointer_is_a.cc new file mode 100644 index 0000000..b6dcb95 --- /dev/null +++ b/graphs/cpp/smtptr/shared_pointer_is_a.cc @@ -0,0 +1,47 @@ +#include "shared_pointer.hh" + +class Animal +{ +public: + virtual ~Animal() + {} +}; + +class Cat : public Animal +{ +public: + void meow() + { + std::cout << "Meow!\n"; + } +}; + +class Dog : public Animal +{ +public: + void bark() + { + std::cout << "Woof!\n"; + } +}; + +int main() +{ + SharedPointer<Animal> animalPtr{ new Cat }; + if (animalPtr.is_a<Cat>()) + { // true + std::cout << "The pointer points to a Cat.\n"; + } + + SharedPointer<Animal> animalPtr2{ new Dog }; + if (animalPtr2.is_a<Cat>()) + { // false + std::cout << "The pointer points to a Cat.\n"; + } + else if (animalPtr2.is_a<Dog>()) + { + std::cout << "The pointer points to a Dog.\n"; + } + + return 0; +} |
