-
Notifications
You must be signed in to change notification settings - Fork 2
Fixed interpret to C++ #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,27 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_DISPOSABLE_BASE_H | ||
| #define DISPOSABLES_DISPOSABLE_BASE_H | ||
|
|
||
| #include <stack> | ||
|
|
||
|
|
||
|
|
||
|
|
||
| #include "IDisposable.h" | ||
| #include "EnsureExtensions.h" | ||
| #include "../../../Exceptions/cpp/Platform.Exceptions/IgnoredExceptions.h" | ||
| #include "../../../Exceptions/cpp/Platform.Exceptions/ExceptionExtensions.h" | ||
| #include "../../../Exceptions/cpp/Platform.Exceptions/Ensure.h" | ||
|
|
||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| class DisposableBase : public IDisposable | ||
| { | ||
| private: static readonly ConcurrentStack<WeakReference<DisposableBase>> _disposablesWeekReferencesStack = ConcurrentStack<WeakReference<DisposableBase>>(); | ||
| private: static std::stack<std::weak_ptr<DisposableBase>> _disposablesWeekReferencesStack; | ||
|
|
||
| private: volatile std::int32_t _disposed; | ||
| private: volatile std::atomic<std::int32_t> _disposed; | ||
|
|
||
| public: bool IsDisposed() | ||
| public: bool IsDisposed() override | ||
| { | ||
| return _disposed > 0; | ||
| } | ||
|
|
@@ -26,29 +41,34 @@ | |
| return false; | ||
| } | ||
|
|
||
| static DisposableBase() { std::atexit(OnProcessExit); } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove static constructor?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I probably should have commented on that. But you can do it like this: https://stackoverflow.com/questions/1197106/static-constructors-in-c-i-need-to-initialize-private-static-objects
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes you can add an inner class with |
||
|
|
||
| protected: DisposableBase() | ||
| public: DisposableBase() | ||
| { | ||
| std::shared_ptr<DisposableBase> this_ptr = std::shared_ptr<DisposableBase>(this); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bad and not working solution. If we create an object of this class on the stack, then after exiting the constructor, its destructor will be called, and the program will crash due to
class DisposableBase : public std::enable_shared_from_this<DisposableBase>, public IDisposable { /*...*/};
auto this_weak = weak_from_this(); |
||
| std::weak_ptr<DisposableBase> this_weak = std::weak_ptr<DisposableBase>(this_ptr); | ||
|
|
||
|
|
||
| _disposed = 0; | ||
| _disposablesWeekReferencesStack.Push(WeakReference<DisposableBase>(this, false)); | ||
| _disposablesWeekReferencesStack.push(this_weak); | ||
| std::atexit(OnProcessExit); | ||
| } | ||
|
|
||
| ~DisposableBase() { Destruct(); } | ||
| //TODO: завязывайте с вызовом всякой виртуальщины в конструкторе/деструкторе | ||
| //~DisposableBase() { Destruct(); } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we cannot call virtual methods in destructor?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because clang says "Inspection' Virtual call from constructor or destructor' " In addition, you can look at these two codes: In principle, this problem can be easily solved, but I'm not sure that it will be in the style of C# Disposables class DisposableWrapper {
DisposableBase* disposableObject;
public:
DisposableWrapper(DisposableBase* disposableObject) : disposableObject(disposableObject) {}
~DisposableWrapper() {
if(disposableObject != null)
disposableObject->Dispose(...);
else
.....
delete disposableObject;
}
};
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, we can skip it at the moment, and force child implementations to call
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll try to figure it out |
||
|
|
||
| public: virtual void Dispose(bool manual, bool wasDisposed) = 0; | ||
|
|
||
| protected: virtual void Dispose(bool manual, bool wasDisposed) = 0; | ||
|
|
||
| public: void Dispose() | ||
| public: void Dispose() override | ||
| { | ||
| this->Dispose(true); | ||
| GC.SuppressFinalize(this); | ||
| } | ||
|
|
||
| public: void Destruct() | ||
| public: void Destruct() override | ||
| { | ||
| try | ||
| { | ||
| if (!IsDisposed) | ||
| if (!IsDisposed()) | ||
| { | ||
| this->Dispose(false); | ||
| } | ||
|
|
@@ -59,30 +79,37 @@ | |
| } | ||
| } | ||
|
|
||
| protected: virtual void Dispose(bool manual) | ||
| public: virtual void Dispose(bool manual) | ||
| { | ||
| auto originalDisposedValue = Interlocked.CompareExchange(ref _disposed, 1, 0); | ||
| int compare_value = 1; | ||
| bool originalDisposedValue = _disposed.compare_exchange_weak(compare_value, 0); | ||
| auto wasDisposed = originalDisposedValue > 0; | ||
| if (wasDisposed && !AllowMultipleDisposeCalls && manual) | ||
| if (wasDisposed && !AllowMultipleDisposeCalls() && manual) | ||
| { | ||
| Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, this, ObjectName, "Multiple dispose calls are not allowed. Override AllowMultipleDisposeCalls property to modify behavior."); | ||
| Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, this, ObjectName(), "Multiple dispose calls are not allowed. Override AllowMultipleDisposeCalls property to modify behavior."); | ||
| } | ||
| if (AllowMultipleDisposeAttempts || !wasDisposed) | ||
| if (AllowMultipleDisposeAttempts() || !wasDisposed) | ||
| { | ||
| this->Dispose(manual, wasDisposed); | ||
| } | ||
| } | ||
|
|
||
| private: static void OnProcessExit() | ||
| { | ||
| while (_disposablesWeekReferencesStack.TryPop(out WeakReference<DisposableBase> weakReference)) | ||
| while (!_disposablesWeekReferencesStack.empty()) | ||
| { | ||
| if (weakReference.TryGetTarget(out DisposableBase disposable)) | ||
| auto weakReference = _disposablesWeekReferencesStack.top(); | ||
| _disposablesWeekReferencesStack.pop(); | ||
|
|
||
| if (auto disposable = weakReference.lock()) | ||
| { | ||
| GC.SuppressFinalize(disposable); | ||
| disposable.Destruct(); | ||
| disposable->Destruct(); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| std::stack<std::weak_ptr<Platform::Disposables::DisposableBase>> Platform::Disposables::DisposableBase::_disposablesWeekReferencesStack = std::stack<std::weak_ptr<DisposableBase>>(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this line complied with no errors?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, static fields in C++ leave much to be desired. This seems to be solved via 'Instance'.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a template class library, and we use C#-like style. So, please, move this initialization inside class definition scope.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In C++, you can't initialize any static fields inside a class. In an ideal implementation, this should generally be done in a file .cpp of the following format: //in the CLASS.cpp file
#include "CLASS.h"
/*type*/ CLASS::static_field = ...;
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is possible if you use |
||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,17 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_DISPOSABLE_T1_T2_H | ||
| #define DISPOSABLES_DISPOSABLE_T1_T2_H | ||
|
|
||
| #include "Disposal.h" | ||
| #include "Disposable[T].h" | ||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| template <typename ...> class Disposable; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove default template root? |
||
|
|
||
| template <typename TPrimary, typename TAuxiliary> class Disposable<TPrimary, TAuxiliary> : public Disposable<TPrimary> | ||
| { | ||
| public: const TAuxiliary AuxiliaryObject; | ||
| public: Platform::Delegates::MulticastDelegate<Disposal> OnDispose; | ||
| public: const TPrimary Object; | ||
|
|
||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject, std::function<void(TPrimary, TAuxiliary)> action) | ||
| : Disposable<TPrimary>(object) | ||
|
|
@@ -18,11 +26,11 @@ | |
| }; | ||
| } | ||
|
|
||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject, std::function<void()> action) : Disposable<TPrimary>(object, action) { return AuxiliaryObject = auxiliaryObject; } | ||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject, std::function<void()> action) : Disposable<TPrimary>(object, action) { AuxiliaryObject = auxiliaryObject; } | ||
|
|
||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject, Disposal disposal) : Disposable<TPrimary>(object, disposal) { return AuxiliaryObject = auxiliaryObject; } | ||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject, Disposal disposal) : Disposable<TPrimary>(object, disposal) { AuxiliaryObject = auxiliaryObject; } | ||
|
|
||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject) : Disposable<TPrimary>(object) { return AuxiliaryObject = auxiliaryObject; } | ||
| public: Disposable(TPrimary object, TAuxiliary auxiliaryObject) : Disposable<TPrimary>(object) { AuxiliaryObject = auxiliaryObject; } | ||
|
|
||
| public: Disposable(TPrimary object) : Disposable<TPrimary>(object) { } | ||
|
|
||
|
|
@@ -44,5 +52,9 @@ | |
| AuxiliaryObject.TryDispose(); | ||
| Object.TryDispose(); | ||
| } | ||
|
|
||
|
|
||
| }; | ||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,14 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_DISPOSABLE_T_H | ||
| #define DISPOSABLES_DISPOSABLE_T_H | ||
|
|
||
|
|
||
| #include "Disposal.h" | ||
| #include "Disposable.h" | ||
|
|
||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| template <typename ...> class Disposable; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove default template root? |
||
|
|
||
| template <typename T> class Disposable<T> : public Disposable<> | ||
| { | ||
| public: const T Object; | ||
|
|
@@ -17,9 +25,9 @@ | |
| }; | ||
| } | ||
|
|
||
| public: Disposable(T object, std::function<void()> action) : Disposable<>(action) { return Object = object; } | ||
| public: Disposable(T object, std::function<void()> action) : Disposable<>(action) { Object = object; } | ||
|
|
||
| public: Disposable(T object, Disposal disposal) : Disposable<>(disposal) { return Object = object; } | ||
| public: Disposable(T object, Disposal disposal) : Disposable<>(disposal) { Object = object; } | ||
|
|
||
| public: Disposable(T object) { Object = object; } | ||
|
|
||
|
|
@@ -33,8 +41,15 @@ | |
|
|
||
| protected: void Dispose(bool manual, bool wasDisposed) override | ||
| { | ||
| base.Dispose(manual, wasDisposed); | ||
| // о нет так можно делать только в visual c++ | ||
| // __super::Dispose(manual, wasDisposed) | ||
| // ---------------------------------- | ||
| // base.Dispose(manual, wasDisposed); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can try to use |
||
|
|
||
| RaiseOnDisposeEvent(manual, wasDisposed); | ||
| Object.TryDispose(); | ||
| } | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,9 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_DISPOSAl_H | ||
| #define DISPOSABLES_DISPOSAl_H | ||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| using Disposal = void(bool, bool); | ||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,29 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_ENSURE_EXTENSION_H | ||
| #define DISPOSABLES_ENSURE_EXTENSION_H | ||
|
|
||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| class EnsureExtensions | ||
| { | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable &disposable, std::string objectName, std::string message) | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable* disposable, std::string objectName, std::string message) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you change the reference to pointer here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can fix this
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I cannot fix
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because any class with undefined virtual methods(virtual ... foo (...) = 0;) can only be a pointer. IDisposable is exactly like this
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did an experiment. I found that it is possible to pass abstract class by reference. It was based on an idea from Stack Overflow, which I found using |
||
| { | ||
| if (disposable.IsDisposed) | ||
| if (disposable->IsDisposed()) | ||
| { | ||
| throw std::runtime_error(std::string("Attempt to access disposed object [").append(objectName).append("]: ").append(message).append(1, '.')); | ||
| } | ||
| } | ||
|
|
||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable &disposable, std::string objectName) { NotDisposed(root, disposable, objectName, {}); } | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable* disposable, std::string objectName) { NotDisposed(root, disposable, objectName, {}); } | ||
|
|
||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable &disposable) { NotDisposed(root, disposable, {}, {}); } | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureAlwaysExtensionRoot root, IDisposable* disposable) { NotDisposed(root, disposable, {}, {}); } | ||
|
|
||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable &disposable, std::string objectName, std::string message) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, objectName, message); } | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable* disposable, std::string objectName, std::string message) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, objectName, message); } | ||
|
|
||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable &disposable, std::string objectName) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, objectName, {}); } | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable* disposable, std::string objectName) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, objectName, {}); } | ||
|
|
||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable &disposable) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, {}, {}); } | ||
| public: static void NotDisposed(Platform::Exceptions::ExtensionRoots::EnsureOnDebugExtensionRoot root, IDisposable* disposable) { Platform::Disposables::EnsureExtensions::NotDisposed(Platform::Exceptions::Ensure::Always, disposable, {}, {}); } | ||
| }; | ||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,10 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_IDISPOSABLE_H | ||
| #define DISPOSABLES_IDISPOSABLE_H | ||
|
|
||
| #include "System.IDisposable.h" | ||
|
|
||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| class IDisposable : public System::IDisposable | ||
| { | ||
|
|
@@ -7,4 +13,6 @@ | |
|
|
||
| virtual void Destruct() = 0; | ||
| }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Abstract virtual destructor should be added here and in all other abstract classes (including System::IDisposable). See also linksplatform/Interfaces#56 |
||
| } | ||
| } | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,20 @@ | ||
| namespace Platform::Disposables | ||
| #ifndef DISPOSABLES_IDISPOSABLE_EXTENSIONS_H | ||
| #define DISPOSABLES_IDISPOSABLE_EXTENSIONS_H | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment there is no need to use header guards in each class file. The template library is included in one piece as a |
||
|
|
||
|
|
||
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| class IDisposableExtensions | ||
| { | ||
| public: static void DisposeIfNotDisposed(IDisposable &disposable) | ||
| { | ||
| if (!disposable.IsDisposed) | ||
| if (!disposable.IsDisposed()) | ||
| { | ||
| disposable.Dispose(); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the point of nulling a local variable? I'm sure the compiler will even cut out this piece of dead code.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In C#, it forces an object to be a candidate for garbage collection if no one else reference it. It also prevents the object from being used again (a safety from stupid mistakes). Translation is incorrect here, should be
*object = nullptrand argument should beT** object