Skip to content
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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

uselessgoddess
Copy link
Member

Могут быть проблемы с подключением(include) из-за странной страсти автора к #pragma once и надеждой на то, что всё будет зависеть только от одного файла(куда собственно и будет includ'иться ).

…получилось сделать из-за довольно странной череды событий)
…получилось сделать из-за довольно странной череды событий)

(См. TODO comment)
(стек на мьютексах? кому он нужен? это ведь детали реализации всё-таки)

((все странности помечены знаменитыми TODO comments))
Copy link
Member

@Konard Konard left a 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>
Copy link
Member

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
Copy link
Member

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)
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot fix

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Member Author

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

Copy link
Member

@Konard Konard Mar 1, 2021

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);
Copy link
Member

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;
Copy link
Member

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;
Copy link
Member

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); }
Copy link
Member

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.

Copy link
Member Author

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

Copy link
Member

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>>();
Copy link
Member

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?

Copy link
Member Author

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"

Copy link
Member

@Konard Konard Feb 28, 2021

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.

Copy link
Member Author

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 = ...;

Copy link
Member

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(); }
Copy link
Member

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?

Copy link
Member Author

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;
    }
};

Copy link
Member

@Konard Konard Feb 28, 2021

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.

Copy link
Member Author

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;
};
Copy link
Member

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);
Copy link

@poul250 poul250 Mar 3, 2021

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:

  1. Additionally inherit this class from std::enable_shared_from_this
class DisposableBase : public std::enable_shared_from_this<DisposableBase>, public IDisposable { /*...*/};
  1. 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;
Copy link

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.

Copy link
Member

@Konard Konard Mar 6, 2021

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

@Konard
Copy link
Member

Konard commented Mar 7, 2021

At the moment it is decided that the task should be not completed.
#49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants