summaryrefslogtreecommitdiff
path: root/graphs/cpp/smtptr
diff options
context:
space:
mode:
Diffstat (limited to 'graphs/cpp/smtptr')
-rw-r--r--graphs/cpp/smtptr/main.cc20
-rw-r--r--graphs/cpp/smtptr/shared_pointer.hh166
-rw-r--r--graphs/cpp/smtptr/shared_pointer.hxx144
-rw-r--r--graphs/cpp/smtptr/shared_pointer_is_a.cc47
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;
+}