Jump to content

  • Log In with Google      Sign In   
  • Create Account

STL containers and constness


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
9 replies to this topic

#1 mdias   Members   -  Reputation: 793

Like
0Likes
Like

Posted 25 September 2013 - 10:39 AM

Hi

 

I'm facing a problem which I'm unable to solve using STL containers.

 

Consider this:

class Mesh
{
public:
   const std::list<SubMesh>& getSubmeshList();
}

I want to be able to modify the objects contained in the list returned by Mesh::getSubmeshList, but want to disable access to inserting/erasing items from the collection. However, since I'm returning a const reference to the list, I can only use a const_iterator which only gives me access to const items.

 

Is there any way around this without using const_cast? Should I rethink my design?



Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9669

Like
4Likes
Like

Posted 25 September 2013 - 10:47 AM

One option is to return a new container that contains pointers to the SubMesh objects that is store in your Mesh object's list. Another is to make your list contain SubMesh pointers in the first case, which would make the const reference contain const pointers to non-const SubMeshes. 



#3 Cornstalks   Crossbones+   -  Reputation: 6991

Like
3Likes
Like

Posted 25 September 2013 - 10:52 AM

One alternative is to do something like:

class Mesh
{
public:
    std::list<SubMesh>::iterator getSubmeshListBegin()
    {
        return submeshList.begin();
    }

    std::list<SubMesh>::iterator getSubmeshListEnd()
    {
        return submeshList.end();
    }
};
And then just operate on the list using the range iterators. This isn't 100% the same, and would require an additional method if you want an easy way to get the size of the list too, but I can't think of anything closer. Also, if you're using C++11, you can name the methods begin() and end() and then use range-based for loops if you wanted.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#4 mdias   Members   -  Reputation: 793

Like
0Likes
Like

Posted 25 September 2013 - 11:10 AM

Thanks! Great ideas!

 

I had thought of exposing the iterators before, but it looks like it may polute the method list in case I need to expose many lists.

However I just thought of creating a template wrapper class that could expose this info, like so:

template <class T>
class ReadOnlyContainer
{
public:
    ReadOnlyContainer( T& originalContainer );

    T::iterator begin();
    T::iterator end();
    size_t size();

private:
   T& _container;
}

class Mesh
{
public:
     ReadOnlyContainer< std::list<SubMesh> > getSubmeshes();
}

Do you think it's a nice idea? Am I overlooking anything?



#5 Cornstalks   Crossbones+   -  Reputation: 6991

Like
1Likes
Like

Posted 25 September 2013 - 01:24 PM

Do you think it's a nice idea? Am I overlooking anything?

The only thing that really worries me is this: "in case I need to expose many lists." Perhaps too much is being exposed (or too much is being contained in a single class) if you get to this point.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#6 mdias   Members   -  Reputation: 793

Like
0Likes
Like

Posted 25 September 2013 - 02:54 PM


The only thing that really worries me is this: "in case I need to expose many lists." Perhaps too much is being exposed (or too much is being contained in a single class) if you get to this point.

You're right. I don't intend to expose much on this specific Mesh class. I just to avoid an eventual future corner-case where I need to expose several lists. I prefer to think of a better/prettier solution if there is any in order to avoid refactoring later.

 

Thank you for the heads up though :)



#7 dilyan_rusev   Members   -  Reputation: 1068

Like
1Likes
Like

Posted 26 September 2013 - 06:26 AM

I would just advise you against too much forward-thinking. Code for 'now', because you can't possibly predict the future.

When (or rather, if) you need feature X, you will also need Y. And you will have a concrete use case to reason against. Then you will come up with much better interface.

If you still persist, I'd rather make the Mesh class itself a container, like Cornstalks suggested.



#8 Matias Goldberg   Crossbones+   -  Reputation: 3697

Like
0Likes
Like

Posted 26 September 2013 - 09:56 PM

Why do you need so much to allow modify but not allow insertions & deletions?



#9 Reitano   Members   -  Reputation: 551

Like
0Likes
Like

Posted 02 October 2013 - 08:04 AM

Code external to the Mesh class should not depend on its implementation details: in this case, the fact that submeshes are stored in a std::list.

I would suggest the following Mesh interface:

class Mesh
{
public:
  size_t GetSubMeshCount() const;
  SubMesh& GetSubMesh(size_t index);
  const SubMesh& GetSubMesh(size_t index) const;
};

Furthermore, std::list has a memory and performance overhead not justified in this case. Use an std::vector or a raw array or even a buffer of fixed size stored in the Mesh class itself (and a dynamically-allocated array as a fallback if the submeshes count exceeds the fixed limit). Please note that here I am assuming that this Mesh class is for the runtime engine, where performance is critical, and not a tool. In the latter case use whatever container makes your life easier.



#10 Cornstalks   Crossbones+   -  Reputation: 6991

Like
1Likes
Like

Posted 02 October 2013 - 05:50 PM

Furthermore, std::list has a memory and performance overhead not justified in this case.

We don't know that for sure. The major reason one would (should) use a std::list is iterator validity after pushing back and erasing. If the OP does not need iterator validity after these types of operations, then sure, something like std::vector that has better cache performance and O(1) random access would be ideal. But that depends on details the OP did not provide.


[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS