Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Template containers (e.g. QList) not feasible for pointers (some C++ gurus out there?)
Qt 6.11 is out! See what's new in the release blog

Template containers (e.g. QList) not feasible for pointers (some C++ gurus out there?)

Scheduled Pinned Locked Moved General and Desktop
24 Posts 5 Posters 18.4k Views 1 Watching
  • 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.
  • G Offline
    G Offline
    giesbert
    wrote on last edited by
    #13

    [quote author="silicomancer" date="1346334361"]I think the "PointerList<A>" declaration would be a bit more inutitive than the const_cast. [/quote]

    This container also has a leak: try to create a container of const pointers with it. It will result in a method

    @
    int indexOf(const T* const value) const { /.../ }

    // will become
    int indexOf(const const MyPtrClass* const value) const { /.../ }
    @

    whic will create a compiler error :-(

    Nokia Certified Qt Specialist.
    Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

    1 Reply Last reply
    0
    • JKSHJ Online
      JKSHJ Online
      JKSH
      Moderators
      wrote on last edited by
      #14

      [quote author="silicomancer" date="1346334361"]So this is weakness in C++? Lets get even more theoretical... how could this be solved on language level? How does other generic languages prevent this? I think C# doesn't support const-ness at all, is this right?[/quote]You could say that C# doesn't encounter this issue because it's lax with const-ness. If you're not on the lookout for a problem, you're less likely to find one! That leads to other const-ness issues for developers to grapple with: http://stackoverflow.com/questions/114149/const-correctness-in-c-sharp

      [EDIT]: Found this quote in the SO discussion: "Reference itself is immutable unless you specify ref modifier. But referenced data isn't immutable." Sounds just like the situation you've encountered in C++!

      As for how to solve it on the language level... I'm not sure. Never tried to design my own language. But this issue is caused by different "multiplicities" -- the template type could contain information for 1 value (data only) or 2 values (data + pointer), as implicated in your linked article. How to handle all possible combinations of const-choices with 1 keyword?

      In C++, the compiler takes this simple approach:
      @
      if (HAS_CONST_KEYWORD)
      {
      if (IS_POINTER)
      MAKE_POINTER_CONST();
      else
      MAKE_DATA_CONST();
      }
      @

      What we'd need is a way to provide the compiler with instructions -- in a compact yet detailed way -- to follow this decision tree:

      @
      if (HAS_CONST_KEYWORD)
      {
      if (IS_POINTER)
      {
      switch (POINTER_CONST_AFFINITY)
      {
      case POINTER_AND_DATA:
      MAKE_POINTER_CONST();
      MAKE_DATA_CONST();
      break;
      case DATA_ONLY:
      MAKE_DATA_CONST();
      break;
      default: // POINTER_ONLY, as currently supported by C++
      MAKE_POINTER_CONST();
      }
      }
      else
      {
      MAKE_DATA_CONST();
      }
      }
      @

      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

      1 Reply Last reply
      0
      • JKSHJ Online
        JKSHJ Online
        JKSH
        Moderators
        wrote on last edited by
        #15

        [quote author="Gerolf" date="1346335083"]This container also has a leak: try to create a container of const pointers with it. It will result in a method

        @
        int indexOf(const T* const value) const { /.../ }

        // will become
        int indexOf(const const MyPtrClass* const value) const { /.../ }
        @

        whic will create a compiler error :-([/quote]Whoops! Back to my original post I guess: There is no nice way to do this in C++. It doesn't mean C++ is a poorly-designed language, but that there's no way for a complex set of rules to cover all possibilities (just look at human legislation)

        @silicomancer:
        You could un-const your Row1() function, if you're willing

        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

        1 Reply Last reply
        0
        • S Offline
          S Offline
          silicomancer
          wrote on last edited by
          #16

          Very interesting thoughts. Thanx!

          I already considered removing const-ness from the Row1() function. But I fact this will trigger a cascade since I use the function in other const-functions, so this only would defer the problem (but multiply it).

          I will stick to the const-cast and try to ignore it ;-)

          I just had another idea. What is about using smart pointers as arguments? For a smart pointer there is no difference between "const smart_ptr<Type> ptr;" and "smart_ptr<Type> const ptr;", is it? I never used smart pointers in typdefs or templates... but I guess when using a smart pointer as indexof() parameter it could clearly dinstinguish between pointer-to-const an const-pointer. Is this right? Is this a solution?

          1 Reply Last reply
          0
          • JKSHJ Online
            JKSHJ Online
            JKSH
            Moderators
            wrote on last edited by
            #17

            No problem. May you retain your sanity in const hell!

            [quote author="silicomancer" date="1346493063"]For a smart pointer there is no difference between "const smart_ptr<Type> ptr;" and "smart_ptr<Type> const ptr;", is it?[/quote]You're right about those being the same. Unfortunately, that doesn't help you because they're both const-pointers, not const-pointers-to-const-data.

            @
            QList<A*> raw_list;
            QList< std::shared_ptr<A> > smart_list;

            // ...

            raw_list.indexOf(/.../); // Expects const-pointer-to-NON-const-data
            smart_list.indexOf(/.../); // Expects const-pointer-to-NON-const-data
            @

            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

            1 Reply Last reply
            0
            • JKSHJ Online
              JKSHJ Online
              JKSH
              Moderators
              wrote on last edited by
              #18

              Here's a possible approach, if you're willing to put up with a redundant member variable, and a potential security leak:

              @
              class A
              {
              public:
              A()
              {
              // ...
              selfAddress = this;
              }
              int Row1 const { return parent->children.indexOf(self); }

              private:
              QList<A*> children;
              A* parent;
              A* const self; // Dangerous!
              }
              @

              I haven't tested it, but it might break const correctness -- I don't think the compiler would realize if you try to modify a member variable using the "self" pointer in a const function. It would stop you if you tried it via "this".

              Edit: In hindsight, this approach works by creating the same kind of "const back-door" as const_cast. Only, const_cast is safer because the back door is restricted to the place where the casting occurred; the "self" pointer opens that back door in every const function!

              Take-home message: Some tools are hazardous if mis-used. However, when used responsibly, they make life very nice. const_cast is one such tool (a chainsaw is another). We should choose the least dangerous of the tools that can do what we want, and use it carefully.

              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

              1 Reply Last reply
              0
              • S Offline
                S Offline
                silicomancer
                wrote on last edited by
                #19

                Yeah. You are right.

                There is one question I though about yesterday... what exactly is the reason why const-ness of a pointer and of its pointed object aren't coupled in C++? Is there something important we couldn't do using C++ if a pointer has the const-ness of its object?

                Hm. Yes, pointer arithmetics. Rarely used but impossible without separate pointer-const-ness.
                Something more you can think of?

                1 Reply Last reply
                0
                • T Offline
                  T Offline
                  twsimpson
                  wrote on last edited by
                  #20

                  You say pointer arithmetic is rarely used, but it's used all the time in implementations (think of how arrays work).
                  Pointers are values, they just happen to be values that point to other values (memory addresses). Values can be const or non-const, so you have the const-ness of the pointer, and the const-ness of what that pointer points to.
                  For example: Non-const pointers to const objects allow manipulation of the pointer, but protect the data pointed to. Const pointers to non-const objects protect the value of the pointer from changing, while allowing manipulation of the data pointed to.
                  Although it can be a headache sometimes, this gives flexibility and allows the programmer to express their intent more clearly to the compiler, so it can warn you when you're doing something wrong.

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    silicomancer
                    wrote on last edited by
                    #21

                    Array operations? They don't change the pointer itself.

                    Hm. Yes. Its flexibel. But I never needed the flexibility. And I have never seen code that needed that flexibility (except one or two legacy C projects using the mentioned pointer arithmetics e.g. incrementing a pointer instead of using []). But currently I have seen a pretty nasty problem caused by that detail. And I have heared a lot of people being frustated about it.

                    However this is very theoretical since I am sure this will never change in C++ :-)

                    Ok, lets finish this. It seems there is no way around that nasty const-cast and it looks like there even wouldn't be a good solution on language level. A little disappointing though.

                    1 Reply Last reply
                    0
                    • G Offline
                      G Offline
                      giesbert
                      wrote on last edited by
                      #22

                      Maybe the question is weird, but looking at the original code you posted, I do not understand the use case:

                      @
                      class A // e.g. a model item
                      {
                      public:
                      int Row1() const { return parent->children.indexOf(this); }
                      int Row2() const { return parent->children.indexOf(const_cast<A*>(this)); }

                      private:
                         QList<A*> children;
                         A* parent;
                      };
                      

                      @

                      if chidlren are you children, you can just use

                      @
                      int Row1() const { return parent->children.count(); }
                      @

                      if children is a complete tree, or the list of element, which are my siblings, then the naming is weird and the usage too.
                      Typically, you would ask your parent about your row number or you have a member row.
                      But containing a list of children where you search your own row number looks not very convenient.

                      Nokia Certified Qt Specialist.
                      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                      1 Reply Last reply
                      0
                      • S Offline
                        S Offline
                        silicomancer
                        wrote on last edited by
                        #23

                        Yes. That code is a simplified snippet.

                        In the real code, the child asks its parent about the row which is the way QAbstractItemModel works.

                        1 Reply Last reply
                        0
                        • T Offline
                          T Offline
                          twsimpson
                          wrote on last edited by
                          #24

                          I wasn't referencing how raw (C-style) arrays work, but how array-like classes may be implemented in C++

                          1 Reply Last reply
                          0

                          • Login

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