Thread: Read-only list of pointers

  1. #1
    Registered User
    Join Date
    May 2004
    Posts
    73

    Read-only list of pointers

    Hello, gods of c++! I beseech you, lay upon me your vast and infinite knowledge of purity of code.

    It all started with this:

    Code:
    class Level {
    public:
       list<Rock *> rocks;
       ...
    };
    and when I have a const pointer to the Level, I shouldn't be able to modify anything it contained, including any rock in the rocks list. This should have failed:

    Code:
    for (list<Rock *>::const_iterator i = level->rocks.begin(); i != level->rocks.end(); i++)
       (*i)->rockRadius *= 2;
    Of course, it compiled successfully, because while the list may have been constant, it didn't hold pointers to const rocks, just regular rocks. Changing the list to be a list<const Rock *> wouldn't work, because then my Level internals couldn't modify it.

    So I changed to this:

    Code:
    class Level {
       list<Rock *> rocks;
    public:
       const list<const Rock *> *getRocks() const { return (const list<const Rock *> *)&rocks; }
       ...
    };
    And this works fine. Two problems though:
    1. It requires a dirty cast.
    2. It's misleading, it tells the user, "yeah, go ahead and add your const stuff to this list, it won't be modified.", but it's just a lie--it's a pointer to non-const stuff.

    What's the best way to design something like this?

    Thanks!

  2. #2
    Registered User
    Join Date
    May 2004
    Posts
    73
    Right, it shouldn't have failed, but for my purposes, I wish it did. I know why it doesn't fail; I need to know a way to make it so it does fail, so my team doesn't accidentally modify this list.

    Edit: I swear I'm not crazy, there was a post above this one O.o
    Last edited by Verdagon; 02-09-2011 at 07:29 PM. Reason: I'm not crazy

  3. #3
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    You're not crazy. sorry. Maybe you can do is just return the list<const Rock *> by value instead of having to cast it since it's just a list of pointer.

    Code:
    // public method of Level
    list<const Rock*> getRocks() const
    {
       return list<const Rock*>(rocks.begin(),rocks.end() ); 
    }
    Last edited by nimitzhunter; 02-09-2011 at 11:37 PM.
    "All that we see or seem
    Is but a dream within a dream." - Poe

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Instead of exposing the underlying member object data collection, expose a begin() and end() method on your Level class, which returns your own iterator class supporting the necessary methods such as ++.
    This way you isolate the user of the class from how it is represented internally, and can do what you want without any non-standards-compliant hacks.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Registered User
    Join Date
    May 2004
    Posts
    73
    But isn't that a lot of overhead per call?

    If there's no easy way to do it, I suppose I can code my own list class that will do this... I was hoping there was something simple I was missing.

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I think you cannot use normal list iterators because the language rules do not propagate constness the way you want.

    However, you should be able to use user-defined iterator wrappers that enforce the rules of your choice.

    It seems that boost's indirect_iterator can be used to make the pointee immutable. As a bonus, it also removes one level of indirection for the user.

    Code:
    #include <list>
    #include <boost/iterator/indirect_iterator.hpp>
    
    struct Rock
    {
        void non_constant() {}
        void constant() const {}
    };
    
    class Level
    {
        std::list<Rock*> rocks;
    public:
        typedef boost::indirect_iterator<std::list<Rock*>::const_iterator, const Rock> const_iterator;
        const_iterator begin() const { return const_iterator(rocks.begin()); }
        const_iterator end() const { return const_iterator(rocks.end()); }
    };
    
    int main()
    {
        Level* level = new Level;
        for (Level::const_iterator i = level->begin(); i != level->end(); i++) {
            i->non_constant(); //error, discarding const qualifier
            i->constant();
        }
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help sorting a linked list. Beginner
    By scarlet00014 in forum C Programming
    Replies: 1
    Last Post: 09-27-2008, 06:16 PM
  2. Following CTools
    By EstateMatt in forum C Programming
    Replies: 5
    Last Post: 06-26-2008, 10:10 AM
  3. Pleas take a look & give a critique
    By sh3rpa in forum C++ Programming
    Replies: 14
    Last Post: 10-19-2007, 10:01 PM
  4. List class
    By SilasP in forum C++ Programming
    Replies: 0
    Last Post: 02-10-2002, 05:20 PM
  5. singly linked list
    By clarinetster in forum C Programming
    Replies: 2
    Last Post: 08-26-2001, 10:21 PM