-
Notifications
You must be signed in to change notification settings - Fork 2
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
Fixed interpret to C++ #68
base: main
Are you sure you want to change the base?
Conversation
…получилось сделать из-за довольно странной череды событий)
…получилось сделать из-за довольно странной череды событий) (См. TODO comment)
(стек на мьютексах? кому он нужен? это ведь детали реализации всё-таки) ((все странности помечены знаменитыми TODO comments))
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.
Let's start a review.
|
||
#include <Platform.Delegates.h> | ||
#include <Platform.Exceptions.h> |
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.
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.
Choose a reason for hiding this comment
The 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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change the reference to pointer here?
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.
I can fix this
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.
I cannot fix
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.
Why?
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.
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.
Choose a reason for hiding this comment
The 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 С++ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can try to use Disposable<>::Dispose(manual, wasDisposed);
here.
{ | ||
template <typename ...> class Disposable; |
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.
Why did you remove default template root?
{ | ||
template <typename ...> class Disposable; |
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.
Why did you remove default template root?
@@ -26,29 +41,34 @@ | |||
return false; | |||
} | |||
|
|||
static DisposableBase() { std::atexit(OnProcessExit); } |
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.
Why did you remove static constructor? OnProcessExit
method should be called once per all instances of DisposableBase
.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
} | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this line complied with no errors?
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.
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.
Choose a reason for hiding this comment
The 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.
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++, 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible if you use inline
keyword, look at the example.
} | ||
|
||
~DisposableBase() { Destruct(); } | ||
//TODO: завязывайте с вызовом всякой виртуальщины в конструкторе/деструкторе | ||
//~DisposableBase() { Destruct(); } |
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.
Why we cannot call virtual methods in destructor?
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.
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.
Choose a reason for hiding this comment
The 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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to figure it out
@@ -7,4 +13,6 @@ | |||
|
|||
virtual void Destruct() = 0; | |||
}; |
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.
Abstract virtual destructor should be added here and in all other abstract classes (including System::IDisposable).
See also linksplatform/Interfaces#56
{ | ||
std::shared_ptr<DisposableBase> this_ptr = std::shared_ptr<DisposableBase>(this); |
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.
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();
|
||
protected: void Dispose(bool manual, bool wasDisposed) override { this->RaiseOnDisposeEvent(manual, wasDisposed); } | ||
|
||
protected: void RaiseOnDisposeEvent(bool manual, bool wasDisposed) { this->OnDispose(manual, wasDisposed); } | ||
|
||
public: template <typename T> static bool TryDisposeAndResetToDefault(T* object) | ||
{ | ||
auto result = object.TryDispose(); | ||
auto result = object->TryDispose(); | ||
if (result) | ||
{ | ||
object = 0; |
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.
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 = nullptr
and argument should be T** object
At the moment it is decided that the task should be not completed. |
Могут быть проблемы с подключением(include) из-за странной страсти автора к #pragma once и надеждой на то, что всё будет зависеть только от одного файла(куда собственно и будет includ'иться ).