Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Brainstorm
  4. Implementing many-to-many relationships

Implementing many-to-many relationships

Scheduled Pinned Locked Moved Solved Brainstorm
40 Posts 8 Posters 10.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T TomZ
    1 Mar 2023, 18:19

    @kshegunov said in Implementing many-to-many relationships:

    How is this safer

    Sure you can use weak pointers (or qpointers, or shared pointers), but that just uses more cycles to zero the pointers.

    As I wrote in the original post:

    You could go with weak-pointers, but that sounds like its just adding complexity and not solving the issue.

    There is no difference between checking the null pointer and you checking the iterator be 'end()'. It doesn't solve the problem.

    But the structs only solution itself is much easier to handle, much cheaper on resources (great for embedded) and generally easier to think about.

    K Offline
    K Offline
    kshegunov
    Moderators
    wrote on 2 Mar 2023, 08:52 last edited by kshegunov 3 Feb 2023, 08:52
    #28

    @TomZ said in Implementing many-to-many relationships:

    Sure you can use weak pointers (or qpointers, or shared pointers), but that just uses more cycles to zero the pointers.

    Cycles pretty much irrelevant in business code, I much rather rely on the prefetcher being smart enough to build its heuristic (which it really is!). The only place it truly matters is whenever you're low-level optimizing a hot codepath, like in a heavy calculation. I'd take the additional indirection any day if I can maintain the code more easily in the long-run, which is the typical case for business logic (which appears to be the case here).

    Read and abide by the Qt Code of Conduct

    T 1 Reply Last reply 2 Mar 2023, 14:31
    0
    • K kshegunov
      2 Mar 2023, 08:52

      @TomZ said in Implementing many-to-many relationships:

      Sure you can use weak pointers (or qpointers, or shared pointers), but that just uses more cycles to zero the pointers.

      Cycles pretty much irrelevant in business code, I much rather rely on the prefetcher being smart enough to build its heuristic (which it really is!). The only place it truly matters is whenever you're low-level optimizing a hot codepath, like in a heavy calculation. I'd take the additional indirection any day if I can maintain the code more easily in the long-run, which is the typical case for business logic (which appears to be the case here).

      T Offline
      T Offline
      TomZ
      wrote on 2 Mar 2023, 14:31 last edited by
      #29

      @kshegunov said in Implementing many-to-many relationships:

      Cycles pretty much irrelevant in business code

      you can waste your cycles, for sure.

      As I wrote, it doesn't actually solve the bigger issue, it only solves the problem you introduce when you use pointers. Don't use pointers and the problem doesn't need solving.

      So my suggestion is to not use pointers.

      K 1 Reply Last reply 2 Mar 2023, 16:20
      0
      • T TomZ
        2 Mar 2023, 14:31

        @kshegunov said in Implementing many-to-many relationships:

        Cycles pretty much irrelevant in business code

        you can waste your cycles, for sure.

        As I wrote, it doesn't actually solve the bigger issue, it only solves the problem you introduce when you use pointers. Don't use pointers and the problem doesn't need solving.

        So my suggestion is to not use pointers.

        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 2 Mar 2023, 16:20 last edited by kshegunov 3 Feb 2023, 16:21
        #30

        @TomZ said in Implementing many-to-many relationships:

        Don't use pointers and the problem doesn't need solving.

        You can't not use pointers, and I imagine you know that. Neither in C, nor in C++, nor in assembly. Every heap allocation is a pointer, and even if you don't keep anything in the heap, which is dubious to begin with (with one notable exception), there are other pointers out there like C-like arrays, function pointers, lvalue references, etc.

        Read and abide by the Qt Code of Conduct

        J T 2 Replies Last reply 2 Mar 2023, 16:23
        2
        • K kshegunov
          2 Mar 2023, 16:20

          @TomZ said in Implementing many-to-many relationships:

          Don't use pointers and the problem doesn't need solving.

          You can't not use pointers, and I imagine you know that. Neither in C, nor in C++, nor in assembly. Every heap allocation is a pointer, and even if you don't keep anything in the heap, which is dubious to begin with (with one notable exception), there are other pointers out there like C-like arrays, function pointers, lvalue references, etc.

          J Offline
          J Offline
          JonB
          wrote on 2 Mar 2023, 16:23 last edited by
          #31

          @kshegunov
          Indeed. I don't understand @TomZ's post? Unless he wants to use Python/C#/Rust or whatever and claim they don't use pointers :)

          1 Reply Last reply
          0
          • K kshegunov
            2 Mar 2023, 16:20

            @TomZ said in Implementing many-to-many relationships:

            Don't use pointers and the problem doesn't need solving.

            You can't not use pointers, and I imagine you know that. Neither in C, nor in C++, nor in assembly. Every heap allocation is a pointer, and even if you don't keep anything in the heap, which is dubious to begin with (with one notable exception), there are other pointers out there like C-like arrays, function pointers, lvalue references, etc.

            T Offline
            T Offline
            TomZ
            wrote on 2 Mar 2023, 19:31 last edited by
            #32

            @kshegunov said in Implementing many-to-many relationships:

            You can't not use pointers,

            Please look at the code sample I provided various comments back.

            It also links to some kde git repo which shows this in practice.

            Yes, you can absolutely code "without" pointers. Objects can live on stack, Qt does that in many situations by default for many objects.

            You can have a QList of QStrings. No pointers in your code at all. Same idea.

            M 1 Reply Last reply 2 Mar 2023, 22:16
            0
            • T TomZ
              2 Mar 2023, 19:31

              @kshegunov said in Implementing many-to-many relationships:

              You can't not use pointers,

              Please look at the code sample I provided various comments back.

              It also links to some kde git repo which shows this in practice.

              Yes, you can absolutely code "without" pointers. Objects can live on stack, Qt does that in many situations by default for many objects.

              You can have a QList of QStrings. No pointers in your code at all. Same idea.

              M Offline
              M Offline
              mzimmers
              wrote on 2 Mar 2023, 22:16 last edited by
              #33

              Hey guys - while I (truly) appreciate the points being made, what I was really looking for in my OP was opinions on sensible approaches to architecting this application. I'm more concerned with readability and maintainability than memory leaks.

              It appears that, apart from @SGaist 's original response, most people don't like the idea of intermediate tables, instead managing the relationships from within the respective objects...correct?

              K T 2 Replies Last reply 6 Mar 2023, 10:57
              0
              • M mzimmers
                2 Mar 2023, 22:16

                Hey guys - while I (truly) appreciate the points being made, what I was really looking for in my OP was opinions on sensible approaches to architecting this application. I'm more concerned with readability and maintainability than memory leaks.

                It appears that, apart from @SGaist 's original response, most people don't like the idea of intermediate tables, instead managing the relationships from within the respective objects...correct?

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 6 Mar 2023, 10:57 last edited by
                #34

                @mzimmers said in Implementing many-to-many relationships:

                Hey guys - while I (truly) appreciate the points being made, what I was really looking for in my OP was opinions on sensible approaches to architecting this application. I'm more concerned with readability and maintainability than memory leaks.

                Well, they aren't exclusive and I'd rather make the argument that you shouldn't have leaks at all.

                It appears that, apart from @SGaist 's original response, most people don't like the idea of intermediate tables, instead managing the relationships from within the respective objects...correct?

                I can't speak for everyone, but I certainly don't. I'd rather architect such an application in the usual OO way, where each item is responsible for whatever it is responsible, than to have the god object that knows everything about everybody.

                @TomZ said in Implementing many-to-many relationships:

                Yes, you can absolutely code "without" pointers. Objects can live on stack, Qt does that in many situations by default for many objects.

                Yes, but sometimes, not always. Qt extensively uses owning and non-owning (weak) pointers to QObjects and that's perfectly fine. It will depend on the semantics, not the syntax (which is what a pointer is - syntax).

                You can have a QList of QStrings. No pointers in your code at all. Same idea.

                When it's a data class, and that's only because Qt already wraps the pointer inside an object to hide that detail from you and give you value semantics. This doesn't mean this is applicable to everything, or rather that you should use it for everything. Not everything is a value, so not everything can behave this way.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                0
                • M mzimmers
                  2 Mar 2023, 22:16

                  Hey guys - while I (truly) appreciate the points being made, what I was really looking for in my OP was opinions on sensible approaches to architecting this application. I'm more concerned with readability and maintainability than memory leaks.

                  It appears that, apart from @SGaist 's original response, most people don't like the idea of intermediate tables, instead managing the relationships from within the respective objects...correct?

                  T Offline
                  T Offline
                  TomZ
                  wrote on 6 Mar 2023, 14:00 last edited by TomZ 3 Jun 2023, 14:03
                  #35

                  @mzimmers said in Implementing many-to-many relationships:

                  opinions on sensible approaches to architecting this application.

                  I would architect it the way that I suggested. A bunch of structs that get stored in maps.
                  Relations between those objects happens via ints that are the 'keys' in those maps.

                  Extremely easy to architect. It avoids memory overhead, avoids pointers and avoids the need to have a manager separate from your data classes as the manager IS your datastructure.

                  The "make it a nice API" is what I linked to the existing example which does exactly that in:

                  @TomZ said in Implementing many-to-many relationships:

                  postscript; if you must, you can make all of this the private content of a 'manager' class and provide some helper classes on top to make it look all object-oriented again. (example: manager, pretty-object, implementation).

                  I indeed hope we can get past the point where some don't understand it and say its a stupid idea. That's indeed not productive.

                  J 1 Reply Last reply 6 Mar 2023, 15:00
                  0
                  • T TomZ
                    6 Mar 2023, 14:00

                    @mzimmers said in Implementing many-to-many relationships:

                    opinions on sensible approaches to architecting this application.

                    I would architect it the way that I suggested. A bunch of structs that get stored in maps.
                    Relations between those objects happens via ints that are the 'keys' in those maps.

                    Extremely easy to architect. It avoids memory overhead, avoids pointers and avoids the need to have a manager separate from your data classes as the manager IS your datastructure.

                    The "make it a nice API" is what I linked to the existing example which does exactly that in:

                    @TomZ said in Implementing many-to-many relationships:

                    postscript; if you must, you can make all of this the private content of a 'manager' class and provide some helper classes on top to make it look all object-oriented again. (example: manager, pretty-object, implementation).

                    I indeed hope we can get past the point where some don't understand it and say its a stupid idea. That's indeed not productive.

                    J Offline
                    J Offline
                    JonB
                    wrote on 6 Mar 2023, 15:00 last edited by
                    #36

                    @TomZ said in Implementing many-to-many relationships:

                    avoids pointers

                    Umm, you mean it swaps pointers to memory for integer indexes into a map/array. No guarantee they are still valid/still have the same key as when they were created. Maybe less likely to "crash", more likely to refer to valid but incorrect information?

                    T 2 Replies Last reply 7 Mar 2023, 18:18
                    0
                    • J JonB
                      6 Mar 2023, 15:00

                      @TomZ said in Implementing many-to-many relationships:

                      avoids pointers

                      Umm, you mean it swaps pointers to memory for integer indexes into a map/array. No guarantee they are still valid/still have the same key as when they were created. Maybe less likely to "crash", more likely to refer to valid but incorrect information?

                      T Offline
                      T Offline
                      TomZ
                      wrote on 7 Mar 2023, 18:18 last edited by
                      #37

                      @JonB said in Implementing many-to-many relationships:

                      more likely to refer to valid but incorrect information?

                      Not in my experience, no.

                      Thanks for asking.

                      1 Reply Last reply
                      0
                      • J JonB
                        6 Mar 2023, 15:00

                        @TomZ said in Implementing many-to-many relationships:

                        avoids pointers

                        Umm, you mean it swaps pointers to memory for integer indexes into a map/array. No guarantee they are still valid/still have the same key as when they were created. Maybe less likely to "crash", more likely to refer to valid but incorrect information?

                        T Offline
                        T Offline
                        TomZ
                        wrote on 7 Mar 2023, 18:20 last edited by
                        #38

                        @JonB said in Implementing many-to-many relationships:

                        Umm, you mean it swaps pointers to memory for integer indexes into a map/array.

                        well, yes, but no.

                        You also skip doing 'new' and 'delete'.

                        You also have all data structures in one place and thus avoid any stupid things like 'friend classes' (or large amount of accessors which have the effect of making properties public).

                        It just keeps stuff simple.

                        M 1 Reply Last reply 7 Mar 2023, 19:29
                        0
                        • T TomZ
                          7 Mar 2023, 18:20

                          @JonB said in Implementing many-to-many relationships:

                          Umm, you mean it swaps pointers to memory for integer indexes into a map/array.

                          well, yes, but no.

                          You also skip doing 'new' and 'delete'.

                          You also have all data structures in one place and thus avoid any stupid things like 'friend classes' (or large amount of accessors which have the effect of making properties public).

                          It just keeps stuff simple.

                          M Offline
                          M Offline
                          mzimmers
                          wrote on 7 Mar 2023, 19:29 last edited by
                          #39

                          @TomZ said in Implementing many-to-many relationships:

                          You also skip doing 'new' and 'delete'.

                          Doesn't seem to me that I'd need new/delete anyway, but I do agree that it seems preferable to:

                          • create and maintain a map of Equipment objects (or structs) with a UUID as the key
                          • in the Activity object, maintain a list of Equipment UUIDs.

                          Is this what you had in mind?

                          T 1 Reply Last reply 7 Mar 2023, 20:32
                          0
                          • M mzimmers
                            7 Mar 2023, 19:29

                            @TomZ said in Implementing many-to-many relationships:

                            You also skip doing 'new' and 'delete'.

                            Doesn't seem to me that I'd need new/delete anyway, but I do agree that it seems preferable to:

                            • create and maintain a map of Equipment objects (or structs) with a UUID as the key
                            • in the Activity object, maintain a list of Equipment UUIDs.

                            Is this what you had in mind?

                            T Offline
                            T Offline
                            TomZ
                            wrote on 7 Mar 2023, 20:32 last edited by TomZ 3 Jul 2023, 20:34
                            #40

                            @mzimmers said in Implementing many-to-many relationships:

                            Doesn't seem to me that I'd need new/delete anyway, but I do agree that it seems preferable to:

                            create and maintain a map of Equipment objects (or structs) with a UUID as the key
                            in the Activity object, maintain a list of Equipment UUIDs.

                            Is this what you had in mind?

                            The various comments here went towards using pointers to instances of classes as the relationship. Can't use a raw pointer (safely) without 'new'.

                            If your only objects are the Equipment and the Activity, then yeah, that's pretty simple.

                            as this got confusing, here is a very quick and dirty mockup I just wrote in 5 minutes. Apologies for the roughness.

                            struct PActivity;
                            struct PEquipment;
                            
                            
                            class ManagerPrivate
                            {
                            public:
                            
                                std::map<int, PActivity> m_activities;
                                std::map<int, PEquipment> m_equipments;
                            
                               int m_lastAssignedId = 0;
                            };
                            
                            struct PActivity
                            {
                                QString name;
                            };
                            
                            struct PEquipment
                            {
                                QString name;
                                std::deque<int> activities;
                            }:
                            
                            
                            class Manager
                            {
                            public:
                                ManagerPrivate *d;
                            
                                Activity createActivity();
                            
                            };
                            
                            // ----
                            
                            
                            class Activity
                            {
                            public:
                                explicit Activity(Manager *parent, int n);
                                Activity(); // gives invalid instance.
                                bool isValid() const { return d && n; }
                            
                                QString name() const {
                                    assert(isValid());
                                    auto i = d->m_activities.find(n);
                                    assert(i != d->m_activities.end());
                                    return i->name;
                                }
                            
                                void setName(const QString &name) {
                                    assert(isValid());
                                    auto i = d->m_activities.find(n);
                                    assert(i != d->m_activities.end());
                                    i->name = name;
                                }
                            
                                int id() const { return n; }
                            
                            private:
                                ManagerPrivate *d = nullptr;
                                int n = 0;
                            };
                            
                            class Equipment
                            {
                                explicit explicit(Manager *parent, int n);
                                explicit(); // gives invalid instance.
                                bool isValid() const;
                                QString name() const;
                                void setName(const QString &name);
                            
                                void addActivity(const Activity &a) {
                                    assert(a.isValid());
                                    assert(isValid());
                                    auto i = d->m_equipments.find(n);
                                    assert(i != d->m_equipments.end());
                                    i->activities.push_back(a->id());
                                }
                            private:
                                ManagerPrivate *d = nullptr;
                                int n = 0;
                            }
                            
                            1 Reply Last reply
                            1
                            • M mzimmers has marked this topic as solved on 31 May 2023, 20:07

                            37/40

                            7 Mar 2023, 18:18

                            • Login

                            • Login or register to search.
                            37 out of 40
                            • First post
                              37/40
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved