How to make a std::vector type-safe - c++

I have an obect called an IndexSet, currently defined as a std::vector, that I want to define as a separate type.
I want to be able to interact with it just as though it were a vector, but I also want type protection so that I don't accidentally use a "normal" vector when I want to use an IndexSet.
I have been able to come up with three options for how to do this, none of which please me. I am hoping that there is a fourth that I am missing.
Option #1: typdef
typdef vector<int> IndexSet
This allows me to use an IndexSet exactly as I would a vector, but it gives me zero type protection. I am able to pass a vector into a function expecting an IndexSet with zero complaints.
Option #2: Public Wrapper Class
class IndexSet
{
public:
vector<int> indexes;
};
This will give me type protection, but it requires me to use a level of indirection interacting with it. Instead of saying
set.push_back(1);
I have to say
set.indexes.push_back(1);
Option #3: Private Wrapper Class
class IndexSet
{
public:
push_back....
operator[]...
etc...
private:
vector<int> indexes
};
This will give me both type protection and allow me to interact directly with the IndexSet as though it were a vector, but ONLY if I first create wrapper methods for every single method of std::vector that I want to use with my IndexSet.
Of course, what I'd really like to do is to just create a new class that inherits from vector but has zero implementation of its own, but I know that the standard library containers do not like to be inherited from.
Are there any other options that I'm missing?

Is there some functionality that differs between an IndexSet and a vector? Is there some difference in how these objects are used? If the answer is no, then why do you want to do this?
Your typedef does not suffice only if there is something intrinsically wrong with supplying a std::vector<int> to a functions that expects an IndexSet. That would suggest that an IndexSet does not satisfy an is-a relationship with respect to std::vector<int>. That in turn means that even if you could public inheritance, you shouldn't be doing so.
If the relationship is implemented-by rather than is-a, this suggests using either containment or private (and possibly protected) inheritance. This is much safer than public inheritance from a container class because programmers who use your class have to go out of their way to get a base class pointer. (The way to do it is to use a C-style cast. C-style casts can convert a derived type to a parent class even if the inheritance is not public.)
The advantage of using private inheritance in instead of containment in this case is that you can easily promote selected inherited member functions from private to protected via the using statement. You would have to write a bunch of wrapper functions if you used containment.
class IndexSet : private std::vector<int> {
public:
// Bunch of constructors, elided.
using std::vector<int>::push_back;
using std::vector<int>::operator[];
using std::vector<int>::cherry_picking_of_only_the_stuff_you_want;
};
Update
There are some non-member functions associated with std::vector, specifically comparison operators and std::swap. Making comparable versions for your IndexSet will require wrapper functions, but there aren't that many (six comparison operators plus std::swap), and you only need these if that functionality makes sense for this class.

Let's face it, one solution has all the advantages and just one disadvantage.
If you subclass std::vector, you just have to make sure you don't mix pointers to std::vector and your class, so nobody will delete a pointer to std::vector when it is actually of your subclass.
Whether this is feasible depends on your project. If this is an object that will be used by alot of people, in a public library, an OSS project etc, you might be safer wrapping it, else just subclass std::vector. You'll be fine.
Don't forget to add a comment at your class interface explaining the dangers. And you might be able do disable casting operators for extra safety (make your ctor explicit, ...).

This sounds like a job for....BOOST_STRONG_TYPEDEF. http://www.boost.org/doc/libs/1_54_0/boost/serialization/strong_typedef.hpp
BOOST_STRONG_TYPEDEF(std::vector<int>, IndexSet)

Related

C++ design: subclass, or are there better ways?

I have a Cheese class. In my program, I deal a lot with collection of cheeses, mostly vector<Cheese> objects.
I want to be able to eat() a cheese collection, something like this:
vector<Cheese> cheeses;
//cheeses = ...
cheeses.eat();
How to do this? How do I add a new member function to the vector<Cheese> class? Should I just subclass the vector<Cheese> class, name the subclass CheeseCollection and add the member function there, or are there any better ways?
Coming from Objective-C, I'm used to categories, which allowed me to add functions ("methods") to classes. Is something like that available in C++, or is it considered more natural to subclass like crazy in C++?
In C++ you simply wouldn’t use a member function for this – use a free function:
void eat(std::vector<Cheese> const& cheeses) {
// …
}
This is a close equivalent to those Obj-C categories even though the syntax differs (and you’re not using member access).
The standard library container classes weren’t designed to be subclassable so that approach will fail. What you could do is use composition instead of inheritance – i.e. have a CheeseCollection class which contains a vector of cheeses as a member. This may have some advantages, depending on your overall design. However, in general the above is the most C++ic solution.
Neither -- what you want is an algorithm. Assuming you have an eat that already knows how to eat one Cheese object, applying it to an entire collection would be something like:
std::for_each(cheeses.begin(), cheeses.end(), eat).
Unlike some other languages, C++ does not maintain a slavish adherence to object orientation, even when it makes no real sense.
One thing you can do is define your own class which uses (encapsulates) the vector:
class Cheeses
{
vector<Cheese> v;
public:
void eat()
{
v.erase();
}
// plus other methods which delegate to the contained vector
};

C++ typedef versus unelaborated inheritance

I have a data structure made of nested STL containers:
typedef std::map<Solver::EnumValue, double> SmValueProb;
typedef std::map<Solver::VariableReference, Solver::EnumValue> SmGuard;
typedef std::map<SmGuard, SmValueProb> SmTransitions;
typedef std::map<Solver::EnumValue, SmTransitions> SmMachine;
This form of the data is only used briefly in my program, and there's not much behavior that makes sense to attach to these types besides simply storing their data. However, the compiler (VC++2010) complains that the resulting names are too long.
Redefining the types as subclasses of the STL containers with no further elaboration seems to work:
typedef std::map<Solver::EnumValue, double> SmValueProb;
class SmGuard : public std::map<Solver::VariableReference, Solver::EnumValue> { };
class SmTransitions : public std::map<SmGuard, SmValueProb> { };
class SmMachine : public std::map<Solver::EnumValue, SmTransitions> { };
Recognizing that the STL containers aren't intended to be used as a base class, is there actually any hazard in this scenario?
There is one hazard: if you call delete on a pointer to a base class with no virtual destructor, you have Undefined Behavior. Otherwise, you are fine.
At least that's the theory. In practice, in the MSVC ABI or the Itanium ABI (gcc, Clang, icc, ...) delete on a base class with no virtual destructor (-Wdelete-non-virtual-dtor with gcc and clang, providing the class has virtual methods) only results in a problem if your derived class adds non-static attributes with non-trivial destructor (eg. a std::string).
In your specific case, this seems fine... but...
... you might still want to encapsulate (using Composition) and expose meaningful (business-oriented) methods. Not only will it be less hazardous, it will also be easier to understand than it->second.find('x')->begin()...
Yes there is:
std::map<Solver::VariableReference, Solver::EnumValue>* x = new SmGuard;
delete x;
results in undefined behavior.
This is one of the controversial point of C++ vs "inheritance based classical OOP".
There are two aspect that must be taken in consideration:
a typedef is introduce another name for a same type: std::map<Solver::EnumValue, double> and SmValueProb are -at all effect- the exact same thing and cna be used interchangably.
a class introcuce a new type that is (by principle) unrelated with anything else.
Class relation are defined by the way the class is "made up", and what lets implicit operations and conversion to be possible with other types.
Outside of specific programming paradigms (like OOP, that associate to the concept of "inhritance" and "is-a" relation) inheritance, implicit constructors, implicit casts, and so on, all do a same thing: let a type to be used across the interface of another type, thus defining a network of possible operations across different types. This is (generally speaking) "polymorphism".
Various programming paradigms exist about saying how such a network should be structured each attempting to optimize a specific aspect of programming, like the representation or runtime-replacable objects (classical OOP), the representation of compile-time replacable objects (CRTP), the use of genreric algorithial function for different types (Generic programming), teh use of "pure function" to express algorithm composition (functional and lambda "captures").
All of them dictates some "rules" about how language "features" must be used, since -being C++ multiparadigm- non of its features satisfy alone the requirements of the paradigm, letting some dirtiness open.
As Luchian said, inheriting a std::map will not produce a pure OOP replaceable type, since a delete over a base-pointer will not know how to destroy the derived part, being the destructor not virtual by design.
But -in fact- this is just a particular case: also pbase->find will not call your own eventually overridden find method, being std::map::find not virtual. (But this is not undefined: it is very well defined to be most likely not what you intend).
The real question is another: is "classic OOP substitution principle" important in your design or not?
In other word, are you going to use your classes AND their bases each other interchangeably, with functions just taking a std::map* or std::map& parameter, pretending those function to call std::map functions resulting in calls to your methods?
If yes, inheritance is NOT THE WAY TO GO. There are no virtual methods in std::map, hence runtime polymorphism will not work.
If no, that is: you're just writing your own class reusing both std::map behavior and interface, with no intention of interchange their usage (in particular, you are not allocating your own classes with new and deletinf them with delete applyed to an std::map pointer), providing just a set of functions taking yourclass& or yourclass* as parameters, that that's perfectly fine. It may even be better than a typedef, since your function cannot be used with a std::map anymore, thus separating the functionalities.
The alternative can be "encapsulation": that is: make the map and explicit member of your class letting the map accessible as a public member, or making it a private member with an accessor function, or rewriting yourself the map interface in your class. You gat finally an unrelated type with tha same interface an its own behavior. At the cost to rewrite the entire interface of something that may have hundredths of methods.
NOTE:
To anyone thinking about the danger of the missing of vitual dtor, note tat encapluating with public visibility won't solve the problem:
class myclass: public std::map<something...>
{};
std::map<something...>* p = new myclass;
delete p;
is UB excatly like
class myclass
{
public:
std::map<something...> mp;
};
std::map<something...>* p = &((new myclass)->mp);
delete p;
The second sample has the same mistake as the first, it is just less common: they both pretend to use a pointer to a partial object to operate on the entire one, with nothing in the partial object letting you able to know what the "containing one" is.

C++: making custom class to work like both container and normal class?

I want to have some myObject which will store a collection (vector-like) of SomeOtherObjects (so, being homogeneous, right?), which should be iterable and accessible via (myObject[i]).SomeOtherObjectField1 but also will have normal members like myObject.doStuff() and myObject.Stuff.
Is there any option to implement such class, or using private std::vector to keep the objects (which I'm trying to avoid - don't like private std:: containers) will be smarter?
Prefer composition over inheritance, if your goal is code reuse. (Inheritance should be used to enable polymorphism, which doesn't seem to be an issue in this case.)
That's looks like the composite design pattern. In short, you have to define the interface of your Object class and derive concrete classes, some being container for others. As said, the composition way is better, but using a common interface is the way to use a 'simple' Object or a 'composite' Object the same way.
my2c
I would use a private std::vector<> and an inline method to return a const reference to it.
Why don't you like member std containers?
Often the right approach to structure lies in clarifying the semantics. You need to ask questions like
"Is myObject a vector<>?". The answer is probably not. If you then follow the principle that a class does one thing (cohesion), then it follows that syntactic sugar around the vector<> is probably not that good.
It tends to follow that the vector<> is a private member. There is no problem with then returning a const reference to it. Returning a non-const reference would break encapulsation - might as well be public data.
If you wish to have:
(myObject[i]).SomeOtherObjectMethod1();
then that is easy enough to implement through operator[](unsigned index). I suspect if you do want that you are better off being consistent and treating myObject as a container in its own right. This means not providing the const ref accessor to the vector<> and implementing the specific accessor methods you really require. This will make client code much easier to understand.

Design of pointer container template

I would like to write a "versatile" class representing the general container storing pointers. Should I use public inheritance or containment?
template <class T>
class List : public std::vector <T *>
{
//...
}
Or
template <class T>
class List
{
private:
std::vector <T *> items;
//...
}
May some problems occur with abstract classes (i.e. virtual destructor)?
If neither proposal is appropriate, what design should I follow (and could you include a short example)?
This is already done for you with Boost's pointer containers.
I do not like boost so I would like to use only C++ 0x00 standard :-).
  — Ian (comment)
If you still want to re-invent these classes, look at the design decisions they made. In particular, they don't inherit from other containers as your first code does.
In fact, just copy the code right out from Boost. This is a header-only library and should be straight-forward (i.e. few implementation-specific workarounds). Boost's license is very liberal, not even requiring you to mention Boost when distributing compiled programs.
How about:
typedef std::vector<boost::shared_ptr<T> > List;
That is, I think it's better to use a resource managing pointer within regular container classes than to reinvent each of the container classes to add resource management capability.
private inheritance is a common tactic for creating classes that are implemented in terms of another. Code that uses the class can't tell that the derived class is derived from a private base, so you won't end up in the sorts of situations that might ordinarily require a virtual destructor.
Use using to import members from the private base to the derived class. For example:
template<class T>
class List:
private std::vector<T>
{
public:
using std::vector<T>::operator[];
using std::vector<T>::size;
};
This is a bit crude, but it gives you some flexibility. You can start out by using private inheritance, and this saves you some typing compared to writing forwarding functions, but you can still write alternative implementations long-hand as required. And then, if/when this becomes inappropriate, you can change the implementation style -- perhaps have a vector as a member, for example, or maybe do everything by hand -- safe in the knowledge that client code won't need to change.
This is ideal for situations where you're pretty sure you'll eventually need a non-standard type of container, but have an existing container type that mostly fits the bill for now. And it's a better medium-term solution than a typedef, because there's no risk of client code accidentally (or on purpose...) using the two types interchangeably.

Class design with vector as a private/public member?

what is the best way to put a container class or a some other class inside a class as private or a public member?
Requirements:
1.Vector< someclass> inside my class
2.Add and count of vector is needed interface
If the container's state is part of the class's invariant, then it should, if possible, be private.
For example, if the container represents a three dimensional vector then part of the invariant might be that it always contains exactly 3 numbers. Exposing it as a public member would allow code external to the class to change the containers size, which in turn could cause problems for any routine which requires the container's size to be constant. Keeping the container private limits the places in your software where the container's size can be modified to the class's member functions.
Whether a member is declared Private or Public depends entirely on your application. Could you give some more detail?
One important point to remember when declaring your member is that if you provide a "getter" to retrieve it, then you are no longer encapsulating that object. Instead, it can be good to write wrapper methods exposing only the functionality you wish to expose.
For example, with a Vector member, you might write an AddItem and Clear method, if that's all the functionality you wish to expose.
Since you're talking about a class, I think it should be private. If you want it to be public, rather create a struct - to make it obvious that you want the members variables to be used.
A viable alternative to exposing the vector member is creating a visitor function (or an internal iterator). This way you obey the law of Demeter better:
class ContWrapper {
std::vector<int> _ints;
public:
class Action {
public:
virtual void accept( int i ) = 0;
};
void each_int( Action& a );
};
Also be very careful when exporting e.g. an std::vector<T> from a library, too: the client code might not use the same STL implementation as you did, so the layout of these member variables may differ!
Make all members private and use accessor methods, this allows you to change the implementation later. Only in very unusual circumstances would I make any data member public.
Remember that chaning the implementation happens more often than you may imagine, its not just a case of changing the type of the container but maybe you want to change the mechanism. Say you were storing names in a list, after a while you may chose to index this list with a hash and would like to have the hash updated every time you add a new name. If your implementation is suitably encapsulated doing this is easy, if you have just exposed the vector you would need to make changes that will adjust the interface (and so the change will ripple out).
If this is new to new you have a read of: http://en.wikipedia.org/wiki/Encapsulation_(classes_-_computers)
There is a third way - sometimes it is better to inherit from the container and override it's methods to achieve your goal (for example thread safety). Anyway, making it public almost always isn't a good idea.
Considering that you want to encapsulate the container inside another class implies that it cannot be public, and also the public methods of your class should not expose anything implementation-specific about the container. That way the implementation of your class (i.e. the container) can be changed without changing its interface.