stl containers style issue

G

Glen Able

Hello,

I've been getting into the STL lately for personal projects and I'm can't
decide whether to wrap containers or not. So the choice is whether to have
a member variable like this:

std::vector<Stuff> m_stuff;

Or to wrap it in a 'StuffVector' class, encapsulating operations on the
vector...

StuffVector m_stuff;

What do the STL aficionados out there prefer?

thanks.
 
M

Moonlit

Hi,

Glen Able said:
Hello,

I've been getting into the STL lately for personal projects and I'm can't
decide whether to wrap containers or not. So the choice is whether to have
a member variable like this:

std::vector<Stuff> m_stuff;

I would go for this, unless you want to use some methods specific for
std:vector<Stuff> (so not generic algoritms or standard vector methods) then
it would make sense to wrap it in a class with the methods.

Just my opinion,

Regards, Ron AF Greve
 
C

cecconeurale

Moonlit said:
Hi,



I would go for this, unless you want to use some methods specific for
std:vector<Stuff> (so not generic algoritms or standard vector methods)
then it would make sense to wrap it in a class with the methods.

Just my opinion,

Regards, Ron AF Greve

i'm not one of the aficionados, but the way i like is:

typedef std::vector<Stuff> StuffVector;

in a general header;
in Italy we say "you get one pigeon with two broad beans"
 
S

Stephen M. Webb

Glen Able said:
Hello,

I've been getting into the STL lately for personal projects and I'm can't
decide whether to wrap containers or not. So the choice is whether to have
a member variable like this:

std::vector<Stuff> m_stuff;

Or to wrap it in a 'StuffVector' class, encapsulating operations on the
vector...

StuffVector m_stuff;

What do the STL aficionados out there prefer?

I generally limit my choices to either using the standard library
object directly,

typedef std::vector<Stuff> StuffBuff;

or wrapping the standard library container and forwarding the few
operations I believe necessary.

class StuffBuff
{
public:
void addStuff(const Stuff&);
void removeStuff(const Stuff&);
private:
typedef std::vector<Stuff> StuffContainer;
StuffContainer m_stuffContainer;
};

Which I choose depends on the application and what interface I want to
present.

I have generally found inheritance to be a useful tool of limited
application: the longer I have used C++, the less I am impressed by
class heirarchies of depth greater than 2 or 3. I have never found it
necessary to derive from standard library objects, with the, uh,
exception of std::exception-based classes and some IOStreams classes.

My rule of thumb says it's better to own (have as a member) than to
loan (borrow the interface of) a non-interface class.
 
G

Gavin Deane

Glen Able said:
Hello,

I've been getting into the STL lately for personal projects and I'm can't
decide whether to wrap containers or not. So the choice is whether to have
a member variable like this:

std::vector<Stuff> m_stuff;

Or to wrap it in a 'StuffVector' class, encapsulating operations on the
vector...

StuffVector m_stuff;

What do the STL aficionados out there prefer?

thanks.

The operations on a vector are already encapsulated in the vector
class. That's the point. If m_stuff needs the behaviour of a
std::vector<Stuff> then you gain nothing by burying that behaviour in
a new type called StuffVector.

There might be times when you have a good reason to want a restricted
subset of the vector functionality. Or you want tighter constraints or
invariants than std::vector offers. In that case you could have a
StuffVector class, with a private std::vector<Stuff> member. Then you
could expose only the bits of the vector interface you need and
implement whatever constraints you need. But I don't think that's what
your question is getting at.

hth
GJD
 
M

Moonlit

Hi,

cecconeurale said:
i'm not one of the aficionados, but the way i like is:

typedef std::vector<Stuff> StuffVector;

Yes, that saves a bit of time when to occasional 'I wanted a car, but now
you have built it I would prefer an aeroplane. Not that much work is it? You
only have to glue on some wings, I guess?' happens.

However I personally do not use the typedef for this, I like to be reminded
in the code what the type actually is, but many developers do it your way,

Regards, Ron AF Greve.
 
G

Glen Able

Thanks to all the respondents for some interesting perspectives!

I've concluded that I'll just do a typedef in most cases, simply because I
find it easier to mentally parse 'StuffVector' rather than
'std::vector<Stuff>'.


I feel similarly to you here, Stephen:
I have generally found inheritance to be a useful tool of limited
application: the longer I have used C++, the less I am impressed by
class heirarchies of depth greater than 2 or 3.

But I'm wondering why you say this:
My rule of thumb says it's better to own (have as a member) than to
loan (borrow the interface of) a non-interface class.

In the case where I want to extend the functionality e.g. add some method
like StuffVector::FindTheBestStuff(), I'm still not keen on creating a
simple wrapper class, because it's such a pain to then have to wrap all the
vector::begin() type stuff where that's required. Isn't it natural here to
derive StuffVector from std::vector<Stuff> and add whatever else I need?

thanks.
 
C

cecconeurale

Moonlit said:
Hi,



Yes, that saves a bit of time when to occasional 'I wanted a car, but now
you have built it I would prefer an aeroplane. Not that much work is it?
You only have to glue on some wings, I guess?' happens.

Well, here is how I glue on wings to my car:

typedef std::vector<Stuff> car;

class airplane : public car {
...
}

I really don't know if this is a way out or simply a mess. However ... It
works. I think it's like specialyzing the template. Obviously you cannot go
back and make a F1 car from an airplane.

bye.
 
G

Gavin Deane

Glen Able said:
Thanks to all the respondents for some interesting perspectives!

I've concluded that I'll just do a typedef in most cases, simply because I
find it easier to mentally parse 'StuffVector' rather than
'std::vector<Stuff>'.


I feel similarly to you here, Stephen:


But I'm wondering why you say this:


In the case where I want to extend the functionality e.g. add some method
like StuffVector::FindTheBestStuff(), I'm still not keen on creating a
simple wrapper class, because it's such a pain to then have to wrap all the
vector::begin() type stuff where that's required. Isn't it natural here to
derive StuffVector from std::vector<Stuff> and add whatever else I need?

First of all, hopefully you are aware that std::vector does not have a
virtual destructor, so you would have to make sure you never deleted a
StuffVector polymorphically. ie

std::vector<Stuff>* p = new StuffVector;
delete p; // undefined behaviour, never do this !!

This is not a reason to never derive from std containers, but it's
something you need to know.

To answer your question, presumably your implementation of
StuffVector::FindTheBestStuff() would only use the public interface of
the std::vector<Stuff> base class (there is no protected interface and
you can't get at the private bits). In which case I think the natural
solution is to implement FindTheBestStuff as a free-standing function
that takes a std::vector<Stuff> (probably by const reference) plus any
other parameters it needs and returns whatever
StuffVector::FindTheBestStuff() would have returned.

You might be interested to read this article by Scott Meyers about
free standing functions and encapsulation. I came across it after
finishing a project where I had decided go down the route equivalent
to having a StuffVector class with a std::vector<Stuff> member. During
the course of the project my design had crumbled around me somewhat,
and the code had got hideously monolithic (and I don't think the
inheritance solution would have helped). I seriously wished I had read
the article before I started.

http://www.cuj.com/documents/s=8042/cuj0002meyers/
 
M

Moonlit

Hi,

cecconeurale said:
Well, here is how I glue on wings to my car:

typedef std::vector<Stuff> car;

class airplane : public car {
...
}
Hmmm, I can drive my car through a carwash, I think I will loose the wings
if I do the same with an earoplane (so an aeroplane appears not to be a
car.)

I really don't know if this is a way out or simply a mess. However ... It
It becomes a mess at the carwash ;-0

works. I think it's like specialyzing the template. Obviously you cannot go
back and make a F1 car from an airplane.

Regards, Ron AF Greve.
 
S

Stephen M. Webb

Glen Able said:
Thanks to all the respondents for some interesting perspectives!
But I'm wondering why you say this:


In the case where I want to extend the functionality e.g. add some method
like StuffVector::FindTheBestStuff(), I'm still not keen on creating a
simple wrapper class, because it's such a pain to then have to wrap all the
vector::begin() type stuff where that's required. Isn't it natural here to
derive StuffVector from std::vector<Stuff> and add whatever else I need?

I have found the key to good code is to keep it simple. A function
should do one thing and one thing only: a class should represent one
concept and one concept only. In the case of a container class, it
contains things. What you do with those things is a separate concept
and so should not be a part of the container class. You will notice
the standard library is (mostly) structured that way, the exceptions
being special optimization cases. Algorithms that operate on
containers (such as FindTheBestStuff()) are separate from the
containers themselves.

Only classes that have limited interfaces to their contained data are
good candidates for wrapping standard containers. For example, the
standard stack class wraps its container. If you need the container
to expose a more generalized interface and you want to add specific
functions based on that interface, derivation isn't superior to a
separate function, since despite having access to the container's
internals you don't want to write code that depends on the container's
implementation anyway. Since the standard containers don't have
virtual destructors, derivation is actually inferior.
 
L

lilburne

Moonlit said:
Yes, that saves a bit of time when to occasional 'I wanted a car, but now
you have built it I would prefer an aeroplane. Not that much work is it? You
only have to glue on some wings, I guess?' happens.

However I personally do not use the typedef for this, I like to be reminded
in the code what the type actually is, but many developers do it your way,

I'd agree with those sentiments.

I think that the justification used for

typedef std::vector<Stuff> StuffVector;

is that a later date you might want to replace

std::vector<Stuff>

with some other contain that has a similar interface:

our::paged_array<Stuff>

without having to trawl the code replacing std::vector with
our::paged_array. However, this never quite works because
users will inevitably know that they are dealing with
std::vector and that knowledge will permeate through the
codebase.

If someone really wants to isolate the fact that they are
using std::vector then they should use containment.
 
E

E. Robert Tisdale

Glen said:
I've been getting into the STL lately for personal projects
and I'm can't decide whether to wrap containers or not.
So the choice is whether to have a member variable like this:

std::vector<Stuff> m_stuff;

Or to wrap it in a 'StuffVector' class,

StuffVector m_stuff;

encapsulating operations on the vector...
What do the STL aficionados out there prefer?

It doesn't matter unless you need to return a reference to m_stuff.
You can do this:

class myClass {
public:
typedef std::vector<Stuff> StuffVector;
private:
StuffVector m_stuff;
public:
StuffVector& stuff(void) {
return mstuff;
}
// . . .
};

int main(int argc, char* argv[]) {
myClass m;
m.stuff()[0] = Stuff();
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,147
Messages
2,570,835
Members
47,382
Latest member
MichaleStr

Latest Threads

Top