• Advertisement
Sign in to follow this  

STL containers and constness

This topic is 1572 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Advertisement

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. 

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites


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 :)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement