Inheriting from STL bitset

S

shaun roe

I want something which is very like a bitset<64> but with a couple of
extra functions: set/get the two 32 bit words, and conversion to
unsigned long long.

I can do this easily by inheriting from bitset<64>, but I know that STL
has no virtual destructor. Can I get around this by calling the
baseclass destructor explicitly in my derived class?

Is there another way to get all of the bitset<64> functionality without
rewriting a lot of code?

cheers

shaun
 
V

Victor Bazarov

shaun said:
I want something which is very like a bitset<64> but with a couple of
extra functions: set/get the two 32 bit words, and conversion to
unsigned long long.

There is no unsigned long long in C++. You must be talking about some
compiler extension you're using.
I can do this easily by inheriting from bitset<64>, but I know that STL
has no virtual destructor. Can I get around this by calling the
baseclass destructor explicitly in my derived class?

You don't need to. Virtual destructor is needed when you delete an object
of derived class using a base class pointer. If you're not going to use
dynamic memory allocation, the destructor of the derived class _will_ call
the destructor of the base class.
Is there another way to get all of the bitset<64> functionality without
rewriting a lot of code?

Do your inheriting thing and see how it goes.

V
 
P

P.J. Plauger

I want something which is very like a bitset<64> but with a couple of
extra functions: set/get the two 32 bit words, and conversion to
unsigned long long.

I can do this easily by inheriting from bitset<64>, but I know that STL
has no virtual destructor. Can I get around this by calling the
baseclass destructor explicitly in my derived class?

Is there another way to get all of the bitset<64> functionality without
rewriting a lot of code?

There's nothing wrong with inheriting from a class without a
virtual destructor, so long as:

1) you don't add member objects in the derived class that might
get sliced away at destruction, or

2) you're careful never to destroy such an object via a pointer
to base (which will slice).

Just do it.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
I

Ivan Vecerina

shaun roe said:
I want something which is very like a bitset<64> but with a couple of
extra functions: set/get the two 32 bit words, and conversion to
unsigned long long.

I can do this easily by inheriting from bitset<64>, but I know that STL
has no virtual destructor. Can I get around this by calling the
baseclass destructor explicitly in my derived class?

Is there another way to get all of the bitset<64> functionality without
rewriting a lot of code?

What's wrong with just providing a couple of non-member functions
that do what you need ?
E.g.:
unsigned long long asUint64( std::bitset<64> const& bs );

What is the point of deriving from a class that has no virtual
functions and no protected members ?
What is even the point of adding creating an additional type
that has no new data members and no new invariants to preserve?
It is possible to derive a new type, but the risks and drawbacks
that result are not worth it IMNSHO.


The problem either way might be that the interface of std::bitset
does not provide efficient r/w access to anything but the lower
bits (that fit in an unsigned long).
Depending on the application, this might be a reason to avoid
std::bitset -- especially since you seem to already be making
the assuption that a 64 bit integer is available on your platform.



Regards,
Ivan
 
J

Julie

Ivan said:
What's wrong with just providing a couple of non-member functions
that do what you need ?
E.g.:
unsigned long long asUint64( std::bitset<64> const& bs );

What is the point of deriving from a class that has no virtual
functions and no protected members ?

What is the point of *not* doing it? No new data? What about new *methods*?

If C++ is supposed to be OO, then why get all procedural whenever you need to
extend the functionality of a class?
 
I

Ivan Vecerina

Julie said:
What is the point of *not* doing it? No new data? What about new
*methods*?

Because doing it:
- creates potential slicing issues (during object copies)
- adds an opportunity for undefined behavior (during delete & array access)
- contradicts the "keep it simple" principle by adding a new type for no
purpose (new class in your hierarchy tree, and potentially
conversions/operators to add).
- may require unnecessary object copying/conversions when interfacing
with code that uses the type being derived from (this is especially true
when deriving from std::string or std::vector).

If C++ is supposed to be OO, then why get all procedural whenever you need to
extend the functionality of a class?


Are you saying that writing obj.f() instead of f(obj) is what defines
object-oriented programming, languages, and design ?

I think you need an objective reason to support the derivation
of a new type. A reason such as:
- being able to override a virtual method
- gaining access to protected data members (but having protected
members in a class with no virtual methods hardly makes sense).
- being able to enforce new invariants, possibly adding data members
(but in this case public inheritance is not an option,
and containment typically should be preferred).
- import a bunch of names into the scope of your class
(this is not OOP, but a technique used in generic programming)

Do you disagree?


Kind regards,
Ivan
 
J

John Harrison

There's nothing wrong with inheriting from a class without a
virtual destructor, so long as:

1) you don't add member objects in the derived class that might
get sliced away at destruction, or

I've never heard this before, could you explain a bit more what the problem
is. At the moment I don't get it.

john
 
P

P.J. Plauger

I've never heard this before, could you explain a bit more what the
problem is. At the moment I don't get it.

Say you have a class B with no virtual destructor. You derive from this
an object D with an extra data member or two. You can easily contrive
a pointer p to just the base part of a derived object d by writing
p = (B *)&d. If you destroy p, all the B destructor knows about is
the B component. Any destructor D has will never get called. You have
*sliced* the object.

OTOH, if B has a virtual destructor, then D automatically has one too.
Destroying p ensures that the whole chain of virtual destructors gets
called in the proper order. No slicing.

So slicing is always a potential problem if you derive from a class
with no virtual destructor, but it is not necessarily a real problem
for the reasons I cited before. The Standard C++ library, in fact,
has a number of classes clearly intended to serve as bases even
though they have no virtual destructors.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
J

John Harrison

P.J. Plauger said:
Say you have a class B with no virtual destructor. You derive from this
an object D with an extra data member or two. You can easily contrive
a pointer p to just the base part of a derived object d by writing
p = (B *)&d. If you destroy p, all the B destructor knows about is
the B component. Any destructor D has will never get called. You have
*sliced* the object.

OTOH, if B has a virtual destructor, then D automatically has one too.
Destroying p ensures that the whole chain of virtual destructors gets
called in the proper order. No slicing.

So slicing is always a potential problem if you derive from a class
with no virtual destructor, but it is not necessarily a real problem
for the reasons I cited before. The Standard C++ library, in fact,
has a number of classes clearly intended to serve as bases even
though they have no virtual destructors.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

OK but isn't that essentially the same as point two which I was familiar
with.

john
 
I

Ivan Vecerina

P.J. Plauger said:
Say you have a class B with no virtual destructor. You derive from this
an object D with an extra data member or two. You can easily contrive
a pointer p to just the base part of a derived object d by writing
p = (B *)&d. If you destroy p, all the B destructor knows about is
the B component. Any destructor D has will never get called. You have
*sliced* the object.

While this is the typical observable behavior, what you formally get
in this case is undefined behavior IIRC. For example, an implementation
could rely on the object's size to determine how to release memory;
deleting an instance of D through a pointer to B could result in
a global corruption of the heap.
I think that this stretches the usual meaning of "slicing"...
OTOH, if B has a virtual destructor, then D automatically has one too.
Destroying p ensures that the whole chain of virtual destructors gets
called in the proper order. No slicing.
As the saying goes: the destructor of a class intended derived from
should be virtual (or else at least protected).
So slicing is always a potential problem if you derive from a class
with no virtual destructor, but it is not necessarily a real problem
for the reasons I cited before. The Standard C++ library, in fact,
has a number of classes clearly intended to serve as bases even
though they have no virtual destructors.
I find it dangerous to make such a statement here without clarifying
which classes you are talking about.
Because I do not think that this would include any container or
string class - but instruments used for generic programming
such as binary_function.

And by the way, would it not be a good idea for the standard
to demand that such base classes used for generic probramming
provide a 'protected:' destructor ?
This could help avoid accidental destruction through a base
class pointer. Would it break any correct code ?



Kind regards,
Ivan
 
P

Pete Becker

Ivan said:
And by the way, would it not be a good idea for the standard
to demand that such base classes used for generic probramming
provide a 'protected:' destructor ?

Life is too short. Focus on actual problems, not hypothetical ones.
This could help avoid accidental destruction through a base
class pointer. Would it break any correct code ?

Would it solve any real problem? How often have you deleted a pointer to
an instance of unary_function?
 
I

Ivan Vecerina

Pete Becker said:
Life is too short. Focus on actual problems, not hypothetical ones.


Would it solve any real problem? How often have you deleted a pointer to
an instance of unary_function?

LOL :)

I do not think that the general problem of Undefined Behavior by deleting
a base class pointer with a non-virtual destructor is a pure hypothesis.

Of course, those who are proficient with generic programming are
the least likely to fall into this trap, which mainly affects novices.
But an empty protected destructor is an inexpensive precaution.


Sorry, I couldn't help but think of this potential issue when I read
P.J. Plaugher's previous statement:

" The Standard C++ library, in fact, has a number of classes clearly
intended to serve as bases even though they have no virtual destructors. "

I find this statement quite misleading within the scope of object-
oriented programming -- and many readers here could misinterpret it.


Best regards,
Ivan
 
P

Pete Becker

Ivan said:
Sorry, I couldn't help but think of this potential issue when I read
P.J. Plaugher's previous statement:

" The Standard C++ library, in fact, has a number of classes clearly
intended to serve as bases even though they have no virtual destructors. "

I find this statement quite misleading within the scope of object-
oriented programming -- and many readers here could misinterpret it.

I'm not interested in "the scope of object-oriented programming." I'm
interested in C++ programming. That statement is true and not at all
misleading: there are, indeed, a number of classes in the Standard C++
Library that are designed to serve as bases but do not have virtual
destructors. Once again: how many times have you deleted a pointer to an
instance of unary_function? This "potential issue" is not real. Get on
with your life.
 
I

Ivan Vecerina

Pete Becker said:
I'm not interested in "the scope of object-oriented programming." I'm
interested in C++ programming. That statement is true and not at all
misleading: there are, indeed, a number of classes in the Standard C++
Library that are designed to serve as bases but do not have virtual
destructors. Once again: how many times have you deleted a pointer to an
instance of unary_function? This "potential issue" is not real. Get on
with your life.

This isn't funny anymore - and I'm disappointed to hear you use that tone.

To move to something constructive:

Could you list a few of these classes of the standard library that
have no virtual destructor and are intended to serve as bases?


Thanks,
Ivan
 
P

Pete Becker

Ivan said:
Could you list a few of these classes of the standard library that
have no virtual destructor and are intended to serve as bases?

Well, the one I've mentioned twice in this thread comes immediately to
mind: unary_function. And, of course, there's it's buddy,
binary_function. And the template named iterator.
 
I

Ivan Vecerina

Pete Becker said:
Well, the one I've mentioned twice in this thread comes immediately to
mind: unary_function. And, of course, there's it's buddy,
binary_function. And the template named iterator.

I just wanted to make sure I'm not missing something. It seems you'll
agree that std::bitset, std::string, standard containers in general,
and iostreams are not part of this list.

I think that this supports my previous comment about the (IMHO)
misleading statement:
"The Standard C++ library, in fact, has a number of classes clearly
intended to serve as bases even though they have no virtual destructors."

Many people here, as the OP, are wondering whether they should derive from
container classes to add some member functions (or data members).
I think the only wise answer is: don't do it.
The quoted sentence mistakenly suggested otherwise.

I would rather point readers to the following article:
http://www.gotw.ca/publications/mill18.htm (see Virtual Question #2)
And the guideline #4 in Herb Sutter's conclusion:
A base class destructor should be either public and virtual, or protected
and nonvirtual.
I think this is a very reasonable advice.

But maybe you can prove me (and Herb's reasoning) wrong.

Could you cite a counterexample where a base class destructor ought to be
both public and non-virtual?



Kind regards,
Ivan
 
A

Alexander Terekhov

Ivan Vecerina wrote:
[...]
Could you cite a counterexample where a base class destructor ought to be
both public and non-virtual?

PMFJI. What's "a base class destructor"? <half wink>

regards,
alexander.
 
P

Pete Becker

Ivan said:
I just wanted to make sure I'm not missing something. It seems you'll
agree that std::bitset, std::string, standard containers in general,
and iostreams are not part of this list.

I think that this supports my previous comment about the (IMHO)
misleading statement:
"The Standard C++ library, in fact, has a number of classes clearly
intended to serve as bases even though they have no virtual destructors."

How does listing some classes that fit this description support you
comment that the statement is misleading?
Many people here, as the OP, are wondering whether they should derive from
container classes to add some member functions (or data members).
I think the only wise answer is: don't do it.
The quoted sentence mistakenly suggested otherwise.

I rarely try to speak for PJ, but what he said is not mistaken. It is
literally true, and it implies a different design choice than the one
that you advocate.
I would rather point readers to the following article:
http://www.gotw.ca/publications/mill18.htm (see Virtual Question #2)
And the guideline #4 in Herb Sutter's conclusion:
A base class destructor should be either public and virtual, or protected
and nonvirtual.
I think this is a very reasonable advice.

It's reasonable to consider it, but it's not reasonable to require it.
There are more things in heaven and earth, Horatio, than are dreamt of
in your philosophy.
 
I

Ivan Vecerina

Alexander Terekhov said:
Ivan Vecerina wrote:
[...]
Could you cite a counterexample where a base class destructor ought to be
both public and non-virtual?

PMFJI. What's "a base class destructor"? <half wink>
You are welcome. I meant: "the destructor of a base class"

To rephrase the question: Is there a useful C++ idiom where a class that
is being derived from has to have a public and non-virtual destructor?


Or in a more verbose way:

Some base classes are designed as mix-ins (e.g. std::binary_function)
and usually aren't intended to be independently instantiated.
Herb's guideline suggests that their destructor should be protected.
[If the benefit of this is debatable, at least I don't see any harm]

Some base classes have virtual functions that can be overriden,
and I think it is widely agreed that their destructor should be virtual.

Prominent authors (Herb Sutter, Scott Meyers) seem to concur that
instantiatable classes that have no virtual member functions should
not be derived from.
Could you suggest a counter-example?



Regards,
Ivan
 
I

Ivan Vecerina

Pete Becker said:
How does listing some classes that fit this description support you
comment that the statement is misleading?

The statement is correct, but will typically be misinterpreted by
novice users. It refers to a specific category of mix-in template
classes, which most likely aren't the ones that a C++ beginner would
think of. They know about strings, streams, and containers such as the
std::bitset mentioned in the subject line -- and deriving from these
classes is unnecessary and considered harmful.

I rarely try to speak for PJ, but what he said is not mistaken. It is
literally true, and it implies a different design choice than the one
that you advocate.

Is it a matter of design choice, or a matter of different scope ?
The example classes you cited have nothing to do with the std::bitset
originally being discussed.
Publicly deriving from std::bitset would be a design choice, but
this is not what you have tried to defend, and several authors
have demonstrated that this has serious caveats. Extending the
interface of the class with non-member functions is seen as preferable,
with no drawback other than the different calling syntax.
It's reasonable to consider it, but it's not reasonable to require it.
There are more things in heaven and earth, Horatio, than are dreamt of
in your philosophy.

I wrote "guideline" and "advice", not rule. And I asked you for an
illuminating counter-example, which unfortunately you declined to provide.


I can think of designs where a destructor should be both virtual
and protected. But I can't think of a useful C++ idiom where a class that
is being derived from needs to have a public and non-virtual destructor.

I'm sure an example can be found, but how realistic would it be?
This is what I would like to find out. I would be thankful if
you, or anyone else, could post such an example.


Cheers,
Ivan
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top