diff --git a/ememory/RefCounter.cpp b/ememory/RefCounter.cpp new file mode 100644 index 0000000..8bd1b44 --- /dev/null +++ b/ememory/RefCounter.cpp @@ -0,0 +1,37 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +ememory::RefCounter::~RefCounter() { + if (m_refCount != 0) { + EMEMORY_ERROR("delete a RefCounted element that is keep by somewhere !! " << m_refCount); + } +} + +void ememory::RefCounter::refKeep() { + m_refCount++; +} + +void ememory::RefCounter::refRelease() { + int refCount = --m_refCount; + if (refCount == 0) { + // No more element ==> remove it. + this->~RefCounter(); + ETK_DELETE(ememory::RefCounter, this); + // NOTE: Do nothing more than this ==> it will not work + return; + } + if (refCount < 0) { + EMEMORY_ERROR("request release a refcounted One more time than needed !! " << m_refCount); + m_refCount = 0; + } +} + +int ememory::RefCounter::getRefCount() const { + return m_refCount; +} \ No newline at end of file diff --git a/ememory/RefCounter.hpp b/ememory/RefCounter.hpp new file mode 100644 index 0000000..447b00c --- /dev/null +++ b/ememory/RefCounter.hpp @@ -0,0 +1,49 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + + +namespace ememory { + /** + * @brief Use the element as a refcounted element + */ + class RefCounter { + protected: + // Virtualize destructor in private to prevent user ot remove it without permition + virtual ~RefCounter(); + private: + int32_t m_refCount = 1; + public: + /** + * @brief Keep a copy of this reference-counted element. + */ + void refKeep(); + /** + * @brief Relese a copy of this reference-counted element. + */ + void refRelease(); + /** + * @brief Get the number of time the object is required. + */ + int32_t getRefCount() const; + /** + * @brief Get the currect class SharedPtr + * @return Request SharedPtr + */ + //ememory::RefPtr refFromThis(); + /** + * @brief Get the currect class SharedPtr + * @return Request const SharedPtr + */ + //const ememory::RefPtr refFromThis() const; + }; +} + +#include + diff --git a/ememory/RefPtr.hpp b/ememory/RefPtr.hpp new file mode 100644 index 0000000..3e04cfd --- /dev/null +++ b/ememory/RefPtr.hpp @@ -0,0 +1,167 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ememory { + class RefCounter; + /** + * @brief ememory::Ref is a smart pointer on RefCounted element. + * this is the good way to use a RefCounter object to not missed to remove one of them. + * + * @note this is smaller than SharedPtr in memory impact and code done, then it is faster. + */ + template + class RefPtr { + private: + EMEMORY_TYPE* m_element = null; //!< Pointer on the Data + public: + #ifndef PARSE_DOXYGEN + template::value + && etk::IsBaseOf::value + , int>::type = 0> + RefPtr(EMEMORY_TYPE2* _element); + #else + /** + * @brief Contructor whith the pointer of data + * @param[in] _element allocated data (RefPtr will remove it) + */ + RefPtr(EMEMORY_TYPE2* _element); + #endif + public: + /** + * @brief Contructor on null + */ + RefPtr(etk::NullPtr); + /** + * @brief Contructor empty + */ + RefPtr(); + /** + * @brief creator (to use wher create a new object (using nuw or ...) + * @param[in] _obj Pointer on the Data + */ + static inline RefPtr create(EMEMORY_TYPE* _obj); + /** + * @brief Contructor (API for casting) + * @param[in] _obj Pointer on the Data + */ + RefPtr(EMEMORY_TYPE* _obj); + /** + * @brief copy Contructor + * @param[in] _obj RefPtr to copy + */ + RefPtr(const RefPtr& _obj); + /** + * @brief copy Contructor + * @param[in] _obj RefPtr to copy + */ + RefPtr(RefPtr&& _obj); + /** + * @brief Destructor + */ + ~RefPtr(); + /** + * @brief Asignement operator + * @param[in] _obj RefPtr to copy + * @return Reference on this + */ + RefPtr& operator= (const RefPtr& _obj); + /** + * @brief Asignement operator (asign null) + * @return Reference on this + */ + RefPtr& operator= (etk::NullPtr); + public: + #ifndef PARSE_DOXYGEN + template::value + , int>::type = 0> + RefPtr(const RefPtr& _obj); + template::value + , int>::type = 0> + RefPtr& operator= (const RefPtr& _obj); + #endif + public: + /** + * @brief Reset the RefPtr ==> Remove data if needed + */ + void reset(); + /** + * @brief Get the number of conencted RefPtr + * @return Number of RefPtr on this data + */ + int useCount() const; + /** + * @brief Check if the RefPtr have an internal data (not null) + * @return true The pointer is not asigned, false otherwise + */ + bool operator==(etk::NullPtr) const; + /** + * @brief Check if two RefPtr are the same data (maybe not the same cast) + * @param[in] _obj Object to compare + * @return true The Object have the same pointer reference, false otherwise + */ + template + bool operator==(const RefPtr& _obj) const; + /** + * @brief Check if the RefPtr have NOT an internal data (null) + * @return true The pointer is asigned, false otherwise + */ + bool operator!=(etk::NullPtr) const; + /** + * @brief Check if two RefPtr are NOT the same data (maybe not the same cast) + * @param[in] _obj Object to compare + * @return true The Object have NOT the same pointer reference, false otherwise + */ + template + bool operator!=(const RefPtr& _obj) const; + /** + * @brief Get a const pointer on the data + * @return Data const pointer + */ + const EMEMORY_TYPE* get() const; + /** + * @brief Get a pointer on the data + * @return Data pointer + */ + EMEMORY_TYPE* get(); + /** + * @brief Const dereferences the stored pointer. + * @return Const pointer on the Data + */ + const EMEMORY_TYPE* operator->() const; + /** + * @brief Dereferences the stored pointer. + * @return Pointer on the Data + */ + EMEMORY_TYPE* operator->(); + /** + * @brief Get a const reference on the data + * @return Data const reference + */ + const EMEMORY_TYPE& operator*() const; + /** + * @brief Get a reference on the data + * @return Data reference + */ + EMEMORY_TYPE& operator*(); + /** + * @brief Swap 2 Object inside the RefPtr + * @param[in] _obj Object to swap with + */ + void swap(RefPtr& _obj); + // TODO: unique + // TODO: bool + }; +} + +#include + diff --git a/ememory/UniquePtr.hpp b/ememory/UniquePtr.hpp index 3340d9a..a8be4b8 100644 --- a/ememory/UniquePtr.hpp +++ b/ememory/UniquePtr.hpp @@ -1,4 +1,8 @@ - +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ #pragma once #include diff --git a/ememory/details/RefPtr.hxx b/ememory/details/RefPtr.hxx new file mode 100644 index 0000000..39ab3e3 --- /dev/null +++ b/ememory/details/RefPtr.hxx @@ -0,0 +1,200 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +template +template::value + && etk::IsBaseOf::value + , int>::type> +ememory::RefPtr::RefPtr(EMEMORY_TYPE2* _element): + m_element(_element) { + EMEMORY_DBG("Create shared"); + if (m_element == null) { + return; + } + EMEMORY_DBG("Check if the user use the memory allocator or personal system..."); + ETK_MEM_CHECK_POINTER(_element); + EMEMORY_DBG(" ==> get previous pointer"); + m_element->refKeep(); + return; +} + +template +ememory::RefPtr ememory::RefPtr::create(EMEMORY_TYPE* _obj) { + EMEMORY_DBG("Create shared"); + ememory::RefPtr tmp{_obj}; + _obj->refRelease(); + return tmp; +} + +template +ememory::RefPtr::RefPtr(): + m_element(null) { + EMEMORY_DBG("Create shared"); +} + +template +ememory::RefPtr::RefPtr(etk::NullPtr): + m_element(null) { + EMEMORY_DBG("Create shared"); +} + +template +ememory::RefPtr::RefPtr(EMEMORY_TYPE* _obj): + m_element(_obj) { + EMEMORY_DBG("Create shared (from a cast)"); + if (m_element == null) { + return; + } + m_element->refKeep(); +} + +template +ememory::RefPtr::~RefPtr() { + EMEMORY_DBG("delete shared"); + reset(); +} + +template +ememory::RefPtr::RefPtr(const ememory::RefPtr& _obj): + m_element(_obj.m_element) { + if (m_element == null) { + return; + } + m_element->refKeep(); +}; + +template +ememory::RefPtr& ememory::RefPtr::operator= (const ememory::RefPtr& _obj) { + reset(); + m_element = _obj.m_element; + if (m_element == null) { + return *this; + } + m_element->refKeep(); + return *this; +} + +template +ememory::RefPtr& ememory::RefPtr::operator= (etk::NullPtr) { + reset(); + return *this; +} + + +template +ememory::RefPtr::RefPtr(ememory::RefPtr&& _obj) { + m_element = _obj.m_element; + _obj.m_element = null; +} + +template +template::value + , int>::type> +ememory::RefPtr::RefPtr(const ememory::RefPtr& _obj): + m_element(const_cast(_obj.get())) { + if (m_element == null) { + return; + } + m_element->refKeep(); +} + +template +template::value + , int>::type> +ememory::RefPtr& ememory::RefPtr::operator= (const RefPtr& _obj) { + reset(); + m_element = const_cast(_obj.get()); + if (m_element == null) { + return *this; + } + m_element->refKeep(); + return *this; +} + +template +void ememory::RefPtr::reset() { + if(m_element == null) { + return; + } + EMEMORY_DBG("reset RefPtr (start)"); + m_element->refRelease(); + m_element = null; + EMEMORY_DBG("reset RefPtr (stop)"); +} + +template +int ememory::RefPtr::useCount() const { + if (m_element == null) { + return 0; + } + return m_element->getRefCount(); +} + +template +bool ememory::RefPtr::operator==(etk::NullPtr) const { + return m_element == null; +} + +template +template +bool ememory::RefPtr::operator==(const RefPtr& _obj) const { + return m_element == _obj.get(); +} + +template +bool ememory::RefPtr::operator!=(etk::NullPtr) const { + return m_element != null; +} + +template +template +bool ememory::RefPtr::operator!=(const RefPtr& _obj) const { + return m_element != _obj.get(); +} + +template +const EMEMORY_TYPE* ememory::RefPtr::get() const { + return m_element; +} + +template +EMEMORY_TYPE* ememory::RefPtr::get() { + return m_element; +} + +template +const EMEMORY_TYPE* ememory::RefPtr::operator->() const { + return m_element; +} + +template +EMEMORY_TYPE* ememory::RefPtr::operator->() { + return m_element; +} + +template +const EMEMORY_TYPE& ememory::RefPtr::operator*() const { + return *m_element; +} + +template +EMEMORY_TYPE& ememory::RefPtr::operator*() { + return *m_element; +} + + +template +void ememory::RefPtr::swap(RefPtr& _obj) { + etk::swap(_obj.m_element, m_element); +} + diff --git a/ememory/memory.hpp b/ememory/memory.hpp index 7ada458..cfb6fd3 100644 --- a/ememory/memory.hpp +++ b/ememory/memory.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -88,4 +89,81 @@ namespace ememory { inline ememory::SharedPtr constPointerCast(const ememory::SharedPtr& _obj) { return ememory::SharedPtr(const_cast(_obj.get()), _obj.getCounter()); } + + + /** + * @brief Create a RefPtr with specific arguments + * @param[in] _args Multiples argument to add in the EMEMORY_TYPE public constructor. + * @return the requested created RefPtr + */ + template::value + , int>::type = 0, + typename... EMEMORY_ARGS> + static ememory::RefPtr makeRef(EMEMORY_ARGS && ..._args) { + return ememory::RefPtr::create(ETK_NEW(EMEMORY_TYPE, etk::forward(_args)...)); + } + /** + * @brief Cast in Dynamic the input RefPtr into an other type like dynamic_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline ememory::RefPtr dynamicRefCast(ememory::RefPtr& _obj) { + return ememory::RefPtr(dynamic_cast(_obj.get())); + } + /** + * @brief CONST Cast in Dynamic the input RefPtr into an other type like dynamic_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline const ememory::RefPtr dynamicRefCast(const ememory::RefPtr& _obj) { + return ememory::RefPtr(dynamic_cast(const_cast(_obj.get()))); + } + /** + * @brief Cast in static the input RefPtr into an other type like static_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline ememory::RefPtr staticRefCast(ememory::RefPtr& _obj) { + return ememory::RefPtr(static_cast(_obj.get())); + } + /** + * @brief CONST Cast in static the input RefPtr into an other type like static_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline const ememory::RefPtr staticRefCast(const ememory::RefPtr& _obj) { + return ememory::RefPtr(static_cast(const_cast(_obj.get()))); + } + /** + * @brief Cast in reinterpret the input RefPtr into an other type like reinterpret_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline ememory::RefPtr reinterpretRefCast(ememory::RefPtr& _obj) { + return ememory::RefPtr(reinterpret_cast(_obj.get())); + } + /** + * @brief CONST Cast in reinterpret the input RefPtr into an other type like reinterpret_cast on pointer + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline const ememory::RefPtr reinterpretRefCast(const ememory::RefPtr& _obj) { + return ememory::RefPtr(reinterpret_cast(const_cast(_obj.get()))); + } + /** + * @brief Cast in const the input RefPtr into an other type like const_cast on pointer (remove constness) + * @param[in] _obj Object To cast + * @return Casted Object + */ + template + inline ememory::RefPtr constRefCast(const ememory::RefPtr& _obj) { + return ememory::RefPtr(const_cast(_obj.get())); + } } diff --git a/lutin_ememory-test.py b/lutin_ememory-test.py index ab95266..71972b6 100644 --- a/lutin_ememory-test.py +++ b/lutin_ememory-test.py @@ -28,6 +28,7 @@ def configure(target, my_module): my_module.add_src_file([ 'test/main.cpp', 'test/testUnique.cpp', + 'test/testRef.cpp', 'test/testShared.cpp', 'test/testWeak.cpp', 'test/testEnableSharedFromThis.cpp', diff --git a/lutin_ememory.py b/lutin_ememory.py index 21bf008..a15a31b 100644 --- a/lutin_ememory.py +++ b/lutin_ememory.py @@ -29,21 +29,25 @@ def configure(target, my_module): # add the file to compile: my_module.add_src_file([ 'ememory/debug.cpp', - 'ememory/Counter.cpp' + 'ememory/Counter.cpp', + 'ememory/RefCounter.cpp', ]) my_module.add_header_file([ 'ememory/debug.hpp', 'ememory/memory.hpp', 'ememory/Counter.hpp', + 'ememory/RefCounter.hpp', + 'ememory/RefPtr.hpp', 'ememory/SharedPtr.hpp', 'ememory/UniquePtr.hpp', 'ememory/WeakPtr.hpp', 'ememory/EnableSharedFromThis.hpp', 'ememory/details/memory.hxx', 'ememory/details/SharedPtr.hxx', + 'ememory/details/RefPtr.hxx', 'ememory/details/WeakPtr.hxx', - 'ememory/details/EnableSharedFromThis.hxx' + 'ememory/details/EnableSharedFromThis.hxx', ]) # build in C++ mode diff --git a/test/testRef.cpp b/test/testRef.cpp new file mode 100644 index 0000000..909ff3a --- /dev/null +++ b/test/testRef.cpp @@ -0,0 +1,208 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +#include "main.hpp" + +namespace { + class MyTestString: + public ememory::RefCounter, + public etk::String { + public: + MyTestString() = default; + MyTestString(const etk::String& _value): + etk::String(_value) { + + } + MyTestString& operator = (const etk::String& _value) { + etk::String::operator=(_value); + return *this; + } + }; +} + +TEST(TestRef, createAndDestroy) { + ememory::RefPtr data = ememory::makeRef("coucou"); + EXPECT_EQ(data.useCount(), 1); + EXPECT_EQ(*data, "coucou"); + EXPECT_EQ(data == null, false); + EXPECT_EQ(data != null, true); + data.reset(); + EXPECT_EQ(data.useCount(), 0); + EXPECT_EQ(data == null, true); + EXPECT_EQ(data != null, false); +} + +TEST(TestRef, createAndDestroy_2) { + ememory::RefPtr data = ememory::RefPtr::create(ETK_NEW(MyTestString, "coucou")); + EXPECT_EQ(data.useCount(), 1); + EXPECT_EQ(*data, "coucou"); + EXPECT_EQ(data == null, false); + EXPECT_EQ(data != null, true); + data.reset(); + EXPECT_EQ(data.useCount(), 0); + EXPECT_EQ(data == null, true); + EXPECT_EQ(data != null, false); +} + +TEST(TestRef, createAndDestroy_3) { + ememory::RefPtr data = ememory::RefPtr::create(new MyTestString("coucou")); + EXPECT_EQ(data.useCount(), 1); + EXPECT_EQ(*data, "coucou"); + EXPECT_EQ(data == null, false); + EXPECT_EQ(data != null, true); + data.reset(); + EXPECT_EQ(data.useCount(), 0); + EXPECT_EQ(data == null, true); + EXPECT_EQ(data != null, false); +} + +TEST(TestRef, copy) { + ememory::RefPtr data = ememory::makeRef("coucou"); + EXPECT_EQ(data.useCount(), 1); + EXPECT_EQ(*data, "coucou"); + ememory::RefPtr dataCopy = data; + EXPECT_EQ(data.useCount(), 2); + EXPECT_EQ(data == dataCopy, true); + EXPECT_EQ(data != dataCopy, false); + data.reset(); + EXPECT_EQ(data == dataCopy, false); + EXPECT_EQ(data != dataCopy, true); + EXPECT_EQ(data.useCount(), 0); + EXPECT_EQ(dataCopy.useCount(), 1); + EXPECT_EQ(*dataCopy, "coucou"); + dataCopy.reset(); + EXPECT_EQ(dataCopy.useCount(), 0); + dataCopy.reset(); + EXPECT_EQ(dataCopy.useCount(), 0); +} + +TEST(TestRef, swap) { + ememory::RefPtr data = ememory::makeRef("coucou"); + EXPECT_EQ(data.useCount(), 1); + EXPECT_EQ(*data, "coucou"); + ememory::RefPtr dataCopy; + EXPECT_EQ(dataCopy.useCount(), 0); + dataCopy.swap(data); + EXPECT_EQ(data.useCount(), 0); + EXPECT_EQ(dataCopy.useCount(), 1); + EXPECT_EQ(*dataCopy, "coucou"); +} + +TEST(TestRef, callOperator) { + ememory::RefPtr data = ememory::makeRef("coucou"); + EXPECT_EQ(data->size(), 6); +} + +static void functionCallRef(etk::String& _data) { + _data = "plop"; +} + +TEST(TestRef, callOperatorStar) { + ememory::RefPtr data = ememory::makeRef("coucou"); + EXPECT_EQ(data->size(), 6); + EXPECT_EQ(*data, "coucou"); + *data = "ragout"; + EXPECT_EQ(data->size(), 6); + EXPECT_EQ(*data, "ragout"); + functionCallRef(*data); + EXPECT_EQ(data->size(), 4); + EXPECT_EQ(*data, "plop"); +} + +namespace { + class basicClass : public ememory::RefCounter { + + }; + + class heritedClass : public basicClass { + + }; +} + +TEST(TestRef, heritage) { + ememory::RefPtr data = ememory::makeRef(); + ememory::RefPtr data2 = data; + ememory::RefPtr data3(data); + EXPECT_NE(data, null); + EXPECT_NE(data2, null); + EXPECT_NE(data3, null); +} + + + + +static uint32_t isDestroy = 0; +namespace { + class testContructDestruct : public ememory::RefCounter { + private: + uint32_t m_addValue; + public: + testContructDestruct(uint32_t _addValue): + m_addValue(_addValue) { + isDestroy += m_addValue; + TEST_DEBUG("Create class " << m_addValue); + } + testContructDestruct(testContructDestruct&& _obj): + m_addValue(_obj.m_addValue) { + _obj.m_addValue = 0; + TEST_DEBUG("move contruction " << m_addValue); + } + virtual ~testContructDestruct() { + if (m_addValue == 0) { + TEST_DEBUG("Remove class (after move)"); + return; + } + TEST_DEBUG("Remove Class " << m_addValue); + isDestroy -= m_addValue; + } + testContructDestruct& operator= (testContructDestruct&& _obj) { + TEST_DEBUG("move operator " << m_addValue); + if (this != &_obj) { + etk::swap(m_addValue, _obj.m_addValue); + } + return *this; + } + }; +} + +TEST(TestRef, destroyElementAtTheCorectMoment) { + isDestroy = 0; + { + etk::Vector> list; + list.pushBack(ememory::makeRef(55)); + EXPECT_EQ(list.size(), 1); + EXPECT_EQ(isDestroy, 55); + auto it = list.erase(list.begin()); + EXPECT_EQ(isDestroy, 0); + EXPECT_EQ(list.size(), 0); + EXPECT_EQ(it, list.end()); + } + EXPECT_EQ(isDestroy, 0); +} + +TEST(TestRef, destroyElementAtTheCorectMoment_2) { + isDestroy = 0; + { + etk::Vector> list; + list.pushBack(ememory::makeRef(4)); + list.pushBack(ememory::makeRef(30)); + list.pushBack(ememory::makeRef(1000)); + list.pushBack(ememory::makeRef(200)); + EXPECT_EQ(list.size(), 4); + EXPECT_EQ(isDestroy, 1234); + auto it = list.erase(list.begin()); + EXPECT_EQ(list.size(), 3); + EXPECT_EQ(isDestroy, 1230); + it = list.erase(list.begin()+1); + EXPECT_EQ(isDestroy, 230); + EXPECT_EQ(list.size(), 2); + } + EXPECT_EQ(isDestroy, 0); +} diff --git a/test/testShared.cpp b/test/testShared.cpp index ecfe383..d4bb21b 100644 --- a/test/testShared.cpp +++ b/test/testShared.cpp @@ -128,68 +128,69 @@ TEST(TestShared, heritage) { static uint32_t isDestroy = 0; - -class testContructDestruct { - private: - uint32_t m_addValue; - public: - testContructDestruct(uint32_t _addValue): - m_addValue(_addValue) { - isDestroy += m_addValue; - TEST_DEBUG("Create class " << m_addValue); - } - testContructDestruct(testContructDestruct&& _obj): - m_addValue(_obj.m_addValue) { - _obj.m_addValue = 0; - TEST_DEBUG("move contruction " << m_addValue); - } - virtual ~testContructDestruct() { - if (m_addValue == 0) { - TEST_DEBUG("Remove class (after move)"); - return; +namespace { + class testContructDestruct { + private: + uint32_t m_addValue; + public: + testContructDestruct(uint32_t _addValue): + m_addValue(_addValue) { + isDestroy += m_addValue; + TEST_DEBUG("Create class " << m_addValue); } - TEST_DEBUG("Remove Class " << m_addValue); - isDestroy -= m_addValue; - } - testContructDestruct& operator= (testContructDestruct&& _obj) { - TEST_DEBUG("move operator " << m_addValue); - if (this != &_obj) { - etk::swap(m_addValue, _obj.m_addValue); + testContructDestruct(testContructDestruct&& _obj): + m_addValue(_obj.m_addValue) { + _obj.m_addValue = 0; + TEST_DEBUG("move contruction " << m_addValue); } - return *this; - } -}; - -class testContructDestruct2 : public ememory::EnableSharedFromThis { - private: - uint32_t m_addValue; - public: - testContructDestruct2(uint32_t _addValue): - m_addValue(_addValue) { - isDestroy += m_addValue; - TEST_DEBUG("Create class " << m_addValue); - } - testContructDestruct2(testContructDestruct2&& _obj): - m_addValue(_obj.m_addValue) { - _obj.m_addValue = 0; - TEST_DEBUG("move contruction " << m_addValue); - } - virtual ~testContructDestruct2() { - if (m_addValue == 0) { - TEST_DEBUG("Remove class (after move)"); - return; + virtual ~testContructDestruct() { + if (m_addValue == 0) { + TEST_DEBUG("Remove class (after move)"); + return; + } + TEST_DEBUG("Remove Class " << m_addValue); + isDestroy -= m_addValue; } - TEST_DEBUG("Remove Class " << m_addValue); - isDestroy -= m_addValue; - } - testContructDestruct2& operator= (testContructDestruct2&& _obj) { - TEST_DEBUG("move operator " << m_addValue); - if (this != &_obj) { - etk::swap(m_addValue, _obj.m_addValue); + testContructDestruct& operator= (testContructDestruct&& _obj) { + TEST_DEBUG("move operator " << m_addValue); + if (this != &_obj) { + etk::swap(m_addValue, _obj.m_addValue); + } + return *this; } - return *this; - } -}; + }; + + class testContructDestruct2 : public ememory::EnableSharedFromThis { + private: + uint32_t m_addValue; + public: + testContructDestruct2(uint32_t _addValue): + m_addValue(_addValue) { + isDestroy += m_addValue; + TEST_DEBUG("Create class " << m_addValue); + } + testContructDestruct2(testContructDestruct2&& _obj): + m_addValue(_obj.m_addValue) { + _obj.m_addValue = 0; + TEST_DEBUG("move contruction " << m_addValue); + } + virtual ~testContructDestruct2() { + if (m_addValue == 0) { + TEST_DEBUG("Remove class (after move)"); + return; + } + TEST_DEBUG("Remove Class " << m_addValue); + isDestroy -= m_addValue; + } + testContructDestruct2& operator= (testContructDestruct2&& _obj) { + TEST_DEBUG("move operator " << m_addValue); + if (this != &_obj) { + etk::swap(m_addValue, _obj.m_addValue); + } + return *this; + } + }; +} TEST(TestShared, destroyElementAtTheCorectMoment) { isDestroy = 0;