Conversation
…получилось сделать из-за довольно странной череды событий)
…получилось сделать из-за довольно странной череды событий) (См. TODO comment)
(стек на мьютексах? кому он нужен? это ведь детали реализации всё-таки) ((все странности помечены знаменитыми TODO comments))
| //#include <Platform.Hashing.h> | ||
|
|
||
| #include <Platform.Delegates.h> | ||
| #include <Platform.Exceptions.h> |
There was a problem hiding this comment.
These includes should be restored.
| @@ -1,13 +1,20 @@ | |||
| namespace Platform::Disposables | |||
| #ifndef DISPOSABLES_IDISPOSABLE_EXTENSIONS_H | |||
| #define DISPOSABLES_IDISPOSABLE_EXTENSIONS_H | |||
There was a problem hiding this comment.
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 cpp/Platform.Disposables/Platform.Disposables.h file.
| 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) |
There was a problem hiding this comment.
Why did you change the reference to pointer here?
There was a problem hiding this comment.
Why?
Because any class with undefined virtual methods(virtual ... foo (...) = 0;) can only be a pointer. IDisposable is exactly like this
There was a problem hiding this comment.
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 С++ abstract class by reference search request in Google.
| // о нет так можно делать только в visual c++ | ||
| // __super::Dispose(manual, wasDisposed) | ||
| // ---------------------------------- | ||
| // base.Dispose(manual, wasDisposed); |
There was a problem hiding this comment.
You can try to use Disposable<>::Dispose(manual, wasDisposed); here.
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| template <typename ...> class Disposable; |
There was a problem hiding this comment.
Why did you remove default template root?
|
|
||
| namespace Platform::Disposables | ||
| { | ||
| template <typename ...> class Disposable; |
There was a problem hiding this comment.
Why did you remove default template root?
| return false; | ||
| } | ||
|
|
||
| static DisposableBase() { std::atexit(OnProcessExit); } |
There was a problem hiding this comment.
Why did you remove static constructor? OnProcessExit method should be called once per all instances of DisposableBase.
There was a problem hiding this comment.
I probably should have commented on that.
There are no static constructors in C++
But you can do it like this: https://stackoverflow.com/questions/1197106/static-constructors-in-c-i-need-to-initialize-private-static-objects
There was a problem hiding this comment.
Yes you can add an inner class with StaticInitializer name. This class should contain only constructor. And it should be immediately embedded as a static field.
| } No newline at end of file | ||
| } | ||
|
|
||
| std::stack<std::weak_ptr<Platform::Disposables::DisposableBase>> Platform::Disposables::DisposableBase::_disposablesWeekReferencesStack = std::stack<std::weak_ptr<DisposableBase>>(); |
There was a problem hiding this comment.
Does this line complied with no errors?
There was a problem hiding this comment.
Yes, static fields in C++ leave much to be desired. This seems to be solved via 'Instance'.
But it works. As my favorite singer sings: "Wet flesh, good size"
There was a problem hiding this comment.
We have a template class library, and we use C#-like style. So, please, move this initialization inside class definition scope.
There was a problem hiding this comment.
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 = ...;
There was a problem hiding this comment.
It is possible if you use inline keyword, look at the example.
|
|
||
| ~DisposableBase() { Destruct(); } | ||
| //TODO: завязывайте с вызовом всякой виртуальщины в конструкторе/деструкторе | ||
| //~DisposableBase() { Destruct(); } |
There was a problem hiding this comment.
Why we cannot call virtual methods in destructor?
There was a problem hiding this comment.
Because clang says "Inspection' Virtual call from constructor or destructor' "
In addition, you can look at these two codes:
https://rextester.com/PUOW20883 (С++)
https://rextester.com/TWL32777 (C#)
In principle, this problem can be easily solved, but I'm not sure that it will be in the style of C# Disposables
For example, something like this:
class DisposableWrapper {
DisposableBase* disposableObject;
public:
DisposableWrapper(DisposableBase* disposableObject) : disposableObject(disposableObject) {}
~DisposableWrapper() {
if(disposableObject != null)
disposableObject->Dispose(...);
else
.....
delete disposableObject;
}
};There was a problem hiding this comment.
Ok, we can skip it at the moment, and force child implementations to call Destruct method in the destructor. Anyway I think we can still call the Destruct method in the destructor, but we also should do it in any implementation of DisposableBase. We also should make base destructor virtual to make child destructor able to run.
There was a problem hiding this comment.
I'll try to figure it out
| @@ -7,4 +13,6 @@ | |||
|
|
|||
| virtual void Destruct() = 0; | |||
| }; | |||
There was a problem hiding this comment.
Abstract virtual destructor should be added here and in all other abstract classes (including System::IDisposable).
See also linksplatform/Interfaces#56
| protected: DisposableBase() | ||
| public: DisposableBase() | ||
| { | ||
| std::shared_ptr<DisposableBase> this_ptr = std::shared_ptr<DisposableBase>(this); |
There was a problem hiding this comment.
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 std::terminate, because we will try to free memory on the stack (invalid operation). If We create an object in the form std::make_shared<T>(), then we will have two different counters for the number of pointers, which will lead to the fact that we will try to free memory in the heap twice (invalid operation).
I suggest doing the following:
- Additionally inherit this class from
std::enable_shared_from_this
class DisposableBase : public std::enable_shared_from_this<DisposableBase>, public IDisposable { /*...*/};- In constructor safely get weak_ptr
auto this_weak = weak_from_this();| auto result = object->TryDispose(); | ||
| if (result) | ||
| { | ||
| object = 0; |
There was a problem hiding this comment.
What's the point of nulling a local variable? I'm sure the compiler will even cut out this piece of dead code.
There was a problem hiding this comment.
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 = nullptr and argument should be T** object
|
At the moment it is decided that the task should be not completed. |
Могут быть проблемы с подключением(include) из-за странной страсти автора к #pragma once и надеждой на то, что всё будет зависеть только от одного файла(куда собственно и будет includ'иться ).