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

remove ConstLegacyControllerMappingVisitor #3636

Merged

Conversation

Be-ing
Copy link
Contributor

@Be-ing Be-ing commented Feb 16, 2021

This class increased coupling and made the code very confusing.

This class increased coupling and made the code very confusing.
@Be-ing Be-ing force-pushed the remove_constlegacycontrollermappingvisitor branch from a7a93a5 to 80f141c Compare February 16, 2021 05:14
@@ -13,8 +12,11 @@ class LegacyHidControllerMapping : public LegacyControllerMapping {
~LegacyHidControllerMapping() override {
}

LegacyControllerMapping* clone() const override {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistently use LegacyControllerMappingPointer everywhere, not plain pointers. Your code already has memory leaks.

Change the typedef from QSharedPointer to std::shared_pointer and then you could use dynamic_pointer_cast instead of dynamic_cast.

http://www.cplusplus.com/reference/memory/dynamic_pointer_cast/

Alternatively use qSharedPointerDynamicCast but I would prefer the standard C++ route instead of dealing with custom Qt re-inventions if not strictly necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll get rid of the QSharedPointer and use std. Might make the diff quite big though.

Copy link
Contributor

Choose a reason for hiding this comment

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

If the diff is too large then keep using QSharedPointer. Doesn't really matter.

Copy link
Contributor Author

@Be-ing Be-ing Feb 16, 2021

Choose a reason for hiding this comment

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

Come to think of it, std::unique_ptr might be a better choice here to help enforce that the cloned object is not shared between threads.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ugh, there's no equivalent of dynamic_pointer_cast for unique_ptr...

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a comment: // Downcast and take ownership on success

It's a shame that you need to write so much code and a comment to get this right. C++ 😩

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🙈

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, a shared pointer is needed. DlgPrefController, ControllerInputMappingTableModel, and ControllerOutputMappingTableModel all share a pointer in the main thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

void HidController::setMapping(std::unique_ptr<LegacyControllerMapping> pMapping) {
    m_pMapping = std::unique_ptr<LegacyHidControllerMapping>(
        dynamic_cast<LegacyHidControllerMapping*>(pMapping.get()));
    if (m_pMapping) {
        pMapping.release();
    }
}

This seems to double free or something? Forget it, I'll use shared pointers and DEBUG_ASSERT that use_count is 1. 🙈

Copy link
Contributor

Choose a reason for hiding this comment

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

Exactly oncy. It is freed later by m_pMapping if the dynamic_cast succeeded or immediately when pMapping goes out of scope. release() doesn't free.

src/controllers/bulk/bulkcontroller.cpp Outdated Show resolved Hide resolved
@Be-ing
Copy link
Contributor Author

Be-ing commented Feb 17, 2021

I gave up trying to mix shared_ptr and unique_ptr. The best I could do was DEBUG_ASSERT that shared_ptr's use_count is 1. That took way more work than it should have.

@Be-ing Be-ing force-pushed the remove_constlegacycontrollermappingvisitor branch from 0b2e4cf to fd670fe Compare February 17, 2021 06:17
@uklotzde
Copy link
Contributor

I gave up trying to mix shared_ptr and unique_ptr. The best I could do was DEBUG_ASSERT that shared_ptr's use_count is 1. That took way more work than it should have.

This happens if you use the wrong abstractions like a shared pointer for everything because it is convenient without thinking about ownership and the consequences. This design was already broken before and don't need to be fixed right now.

src/controllers/bulk/bulkcontroller.cpp Outdated Show resolved Hide resolved
src/controllers/hid/hidcontroller.cpp Outdated Show resolved Hide resolved
src/controllers/midi/midicontroller.cpp Show resolved Hide resolved
@Be-ing Be-ing force-pushed the remove_constlegacycontrollermappingvisitor branch from b59e84b to 44f0168 Compare February 17, 2021 19:19
// LegacyControllerMapping.
// Trying to cast a std::shared_ptr to a std::unique_ptr is not worth the trouble.
// The use_count is 2 at this point, one use by the caller and one use by this class.
VERIFY_OR_DEBUG_ASSERT(pMapping.use_count() == 2) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

had to change this to 2 because C++

wtf is this language 🙃

Copy link
Contributor

Choose a reason for hiding this comment

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

If you pass it with std::move it should (or might?) work as expected. This is what you would also need to do when using a std::unique_ptr.

Copy link
Contributor

@uklotzde uklotzde Feb 17, 2021

Choose a reason for hiding this comment

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

Explicitly enforce the move on the caller site by turning the parameter type into an rvalue reference, i.e. std::shared_ptr<..>&&.

Copy link
Contributor

Choose a reason for hiding this comment

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

All ugly workarounds for missing move semantics and the reason why std::unique_ptr would be a better choice for the parameter type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Casting that magic spell worked 🧙‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I could make a separate uniqueClone method for LegacyControllerMapping? Also ugly, but 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whatever, this works and CI passed. Let's move on.

@Be-ing Be-ing force-pushed the remove_constlegacycontrollermappingvisitor branch from 44f0168 to 4efdeb5 Compare February 17, 2021 19:48
Copy link
Contributor

@uklotzde uklotzde left a comment

Choose a reason for hiding this comment

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

The workaround is brittle but the use count assertion ensures that we will notice early if it does not work as intended. The code before this refactoring worked more or less by chance with implicit and hidden assumptions. Thanks for taking the effort to sort this out! LGTM

@uklotzde uklotzde merged commit 2f423f9 into mixxxdj:main Feb 17, 2021
@Be-ing Be-ing deleted the remove_constlegacycontrollermappingvisitor branch February 17, 2021 22:19
@Be-ing
Copy link
Contributor Author

Be-ing commented Feb 17, 2021

Thank you for review. I think I can start decoupling the legacy mapping system from Controller and MidiController now.

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

Successfully merging this pull request may close these issues.

2 participants