CorresVector : public vector<Corres>{
public:
void addCorres(Corres& c); //it do little more than push_back
function.
}
Or I need to do a composition to do it (i.e storing the vector inside
Corresvector & delegating the necessary functionality). I want to know
that whether in this case (inheriting) is allowed for containers, i.e
will the container will get freed when CorresVector gets destoryed (i.e
vector has a virtual destructor which gets called?)
abir
No, vector does not have a virtual destructor. It doesn't have any
virtual functions. You can inherit from a vector but you can't do so
polymorphically.
Hi abir,
std::vector does not have a virtual destructor.
But it would only need one, if you delete a CorresVector through a pointer
to a base class.
As for the question whether it is the "right" approach, use google and you
will find a lot of different opinions (see e.g.
http://www.thescripts.com/forum/thread63869.html).
Cheers,
Frank
You should not derive from STL container classes. Their destructors are
not virtual.
Although, in my book, composition can be a form of private inheritence.
Why not template the class? In your example, if element class Corres,
whatever that is, overloads the global op<<, you can add features as
shown below. Note that both primitive int and class std::string already
have an overloaded operator<<.
The point here is that if you are going to compose with a std::vector,
do it to add features, otherwise you would not need to wrap the
container.
How you do that is not very complicated:
a) learn how to declare and use templates
b) pass by reference
c) dependant types need the typename keyword
d) overload operators
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
template< typename T >
class Vector
{
std::vector< T > vt;
public:
Vector() : vt() { } // an empty vector of TsSince primitive types
like int and other classes like std::string already have an overload
for global op<<, i can iterate through the elements simply by writing:
std::cout << name_of_container;
~Vector() { }
/* member functions */
size_t size() const { return vt.size(); }
void push_back( const T& r_t ) { vt.push_back( r_t ); }
/* friend op */
friend
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{ // std::vector<T>::iterator is a dependant type
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.vt.begin();
for ( iter; iter != r_v.vt.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};
int main()
{
Vector< int > integers;
for ( int n = 0; n < 5; ++n )
{
integers.push_back( n );
}
std::cout << integers; // op<< overload
Vector< std::string > strings;
strings.push_back( "first string" );
strings.push_back( "second string" );
strings.push_back( "third string" );
strings.push_back( "fourth string" );
std::cout << strings; // op<< overload
return 0;
}
/*
0
1
2
3
4
first string
second string
third string
fourth string
*/
However unlike the code you presented, I need many features of vector
rather than just push_back. Most importantly, I need the iterator
functionality, and want to apply many stl algorithms to CorresVector
just like vector. That says I need to delegate many more functions
rather than size & push_back( say aoo of the iterator traits, const &
non const vercion of begin end etc, reserve, indexing operators, at and
others). It is not difficult, it is tedious!
And in code CorresVector is going to be used only one place, i.e inside
Session class, like,
class Session{
private:
CorresVector _corres;
};
and some reference get methods (const & non const). There is no other
place where it will be used (there is no other place there it can be
used also :) ). Thus I think it will not cause any memory leak in this
particular case(i.e not freeing the elements on destruction). Session
class has a virtual destructor, and hence it will always get destroyed
even when inheriting & storing in SessionManager (a singleton) like
FileSession, OnlineSession etc.
Can you say a yes/no about risk to this specific case?
For general case, I like your answer, and sooner or later will
implement it.
btw Corres means Correspondence (a special kind of distance structure)
Thanks for the reply & the worning.
That should read "you should not polymorphically delete objects of
types derived from STL container classes. STL container classes do not
have virtual destructors."
How is that class superior to this? If used with your program below it
produces the same output.
template <typename T>
class Vector : public std::vector<T>
{
friend std::ostream& operator<<(std::ostream& os, Vector< T >& r_v)
{
typedef typename std::vector< T >::iterator VIter;
VIter iter = r_v.begin();
for ( iter; iter != r_v.end(); ++iter )
{
os << *iter << std::endl;
}
return os;
}
};
> int main()
> {
> Vector< int > integers;
> for ( int n = 0; n < 5; ++n )
> {
> integers.push_back( n );
> }
> std::cout << integers; // op<< overload
>
> Vector< std::string > strings;
> strings.push_back( "first string" );
> strings.push_back( "second string" );
> strings.push_back( "third string" );
> strings.push_back( "fourth string" );
> std::cout << strings; // op<< overload
But your class can't do this unless you go back and change it.
strings.pop_back();
std::cout << strings;
>
> return 0;
> }
>
> /*
> 0
> 1
> 2
> 3
> 4
> first string
> second string
> third string
> fourth string
first string
second string
third string
> */
Gavin Deane
But that's really two different questions. Yes, when CorresVector gets
destroyed, its base will, too. No, if you have a pointer to the base and
you delete that, you have no guarantees of what will happen, because the
base type does not have a virtual destructor.
--
-- Pete
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
yes, of course. But isn't that the goal here?
Otherwise, why bother inheriting from a std::vector?
My class is not superior in any way unless there is a need to protect
the internals or if polymorphism is involved.
>
> template <typename T>
> class Vector : public std::vector<T>
> {
If you inherit publicly, friend is no longer required, the std::vector
is directly accessible.
> friend std::ostream& operator<<(std::ostream& os, Vector< T >& r_v)
> {
> typedef typename std::vector< T >::iterator VIter;
> VIter iter = r_v.begin();
> for ( iter; iter != r_v.end(); ++iter )
> {
> os << *iter << std::endl;
> }
> return os;
> }
> };
or
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <iterator>
template< typename T >
class Vector : public std::vector< T >
{
};
template< typename T >
std::ostream&
operator<<( std::ostream& os, Vector< T >& r_v )
{
std::copy( r_v.begin(),
r_v.end(),
std::ostream_iterator< T > ( std::cout , "\n") );
}
Which again brings us right back to the crux of the issue. In such a
case, why bother inheriting from std::vector? What is the reason?
>
> > int main()
> > {
> > Vector< int > integers;
> > for ( int n = 0; n < 5; ++n )
> > {
> > integers.push_back( n );
> > }
> > std::cout << integers; // op<< overload
> >
> > Vector< std::string > strings;
> > strings.push_back( "first string" );
> > strings.push_back( "second string" );
> > strings.push_back( "third string" );
> > strings.push_back( "fourth string" );
> > std::cout << strings; // op<< overload
>
> But your class can't do this unless you go back and change it.
>
> strings.pop_back();
> std::cout << strings;
Thats obvious. The rest of the interface was not implemented.
>
> Gavin Deane
I doubt polymorphism is the OP's goal, since std::vector doesn't have
any virtual member functions at all.
> #include <iostream>
> #include <ostream>
> #include <string>
> #include <vector>
> #include <iterator>
>
> template< typename T >
> class Vector : public std::vector< T >
> {
> };
>
> template< typename T >
> std::ostream&
> operator<<( std::ostream& os, Vector< T >& r_v )
> {
> std::copy( r_v.begin(),
> r_v.end(),
> std::ostream_iterator< T > ( std::cout , "\n") );
> }
>
> Which again brings us right back to the crux of the issue. In such a
> case, why bother inheriting from std::vector? What is the reason?
That's a design decision for the OP. Depending on the design goal,
there may be options superior to inheritance. Composition may or may
not be one of them.
The point I was making was that lack of a virtual destructor is not
sufficient reason for rejecting inheritance, and that using composition
instead is not necessarily better because you, the programmer, are
required to manually forward all those parts of the std::vector
interface that you need to be accessible to users of the containing
class, whereas inheritance gives you that forwarding for free.
> > But your class can't do this unless you go back and change it.
> > strings.pop_back();
> > std::cout << strings;
> Thats obvious. The rest of the interface was not implemented.
The fact that it has to be implemented manually is the problem.
Gavin Deane
You are basically wanting to "inherit for convenience" - you seem like
a sensible fellow who understands that (a) there are issues with this
approach and (b) knows what those issues are (or at least you do know
from others' replies), so I say go for it.
std::vector doesn't have a virtual dtor (or any virtual functions for
that matter). Since the dtor isn't virtual this would lead to undefined
behavior, but it's easy to do by accident because public inheritance
allows implicit conversion to the base class.
While composition is clearly an option, you might also want to consider
private inheritance:
class CorresVector : private std::vector<Corres> {
public:
using vector::begin;
using vector::end;
using vector::erase;
void add(Corres const &c) { push_back(c); }
// ...
};
Public inheritance is easy, but somewhat dangerous because you can
accidentally (implicitly) convert a pointer to your derived class into a
pointer to the base -- and destroying that leads to undefined behavior.
Composition gives safety, but writing forwarding functions adds work.
Private inheritance is more or less a halfway point, providing the
safety of composition with a little less work -- using declarations are
clearly simpler than forwarding functions, though obviously more work
than a public base class.
--
Later,
Jerry.
The universe is a figment of its own imagination.
No, there's nothing undefined in destroying an object whose type is
derived from a type that does not have a virtual destructor. You ONLY
get undefined behavior if you delete such an object through a pointer to
its base type.
, but it's easy to do by accident because public inheritance
> allows implicit conversion to the base class.
>
This has nothing to do with destruction. Converting to the base type is
slicing, and it's a potential problem regardless of whether the base
type has virtual functions.
>
> Public inheritance is easy, but somewhat dangerous because you can
> accidentally (implicitly) convert a pointer to your derived class into a
> pointer to the base -- and destroying that leads to undefined behavior.
>
> Composition gives safety, but writing forwarding functions adds work.
> Private inheritance is more or less a halfway point, providing the
> safety of composition with a little less work -- using declarations are
> clearly simpler than forwarding functions, though obviously more work
> than a public base class.
>
Okay.
[ ... ]
> No, there's nothing undefined in destroying an object whose type is
> derived from a type that does not have a virtual destructor. You ONLY
> get undefined behavior if you delete such an object through a pointer to
> its base type.
Well, even I can't figure out what I wrote when you pull it apart into
half-sentences, and reply to bits and pieces that were never intended to
represent a complete thought. To clarify what I was trying to say:
1) if you have code like this:
class base {}; // note lack of virtual dtor
class derived : public base {};
base *b = new derived;
// ...
delete b;
You'd get undefined behavior. and:
2) There's absolutely NOTHING you can do in 'derived' to prevent it from
being used in that fashion (or many similar ones that cause similar
problems).
What it comes down to is fairly simple: by using public derivation,
you've _promised_ that a derived can be substituted for a base under any
and all possible circumstances. The problem arises for the simple reason
that this is a lie -- under at least one circumstance (destruction) the
substitution leads to undefined behavior.
In short, even though you _can_ get away with this as long as you're
sufficiently careful about how you use it, it's a lousy idea. Public
derivation has a specific meaning. Unless you really mean it, you
shouldn't say it by using public derivation. Public derivation from a
base class without a virtual dtor asserts a falsehood.
> In article <O8mdnUOccJ4L-YfY...@giganews.com>,
> peteb...@acm.org says...
>
> [ ... ]
>
>> No, there's nothing undefined in destroying an object whose type is
>> derived from a type that does not have a virtual destructor. You ONLY
>> get undefined behavior if you delete such an object through a pointer to
>> its base type.
>
> Well, even I can't figure out what I wrote when you pull it apart into
> half-sentences, and reply to bits and pieces that were never intended to
> represent a complete thought. To clarify what I was trying to say:
>
> 1) if you have code like this:
>
> class base {}; // note lack of virtual dtor
> class derived : public base {};
>
> base *b = new derived;
> // ...
> delete b;
>
> You'd get undefined behavior. and:
>
> 2) There's absolutely NOTHING you can do in 'derived' to prevent it from
> being used in that fashion (or many similar ones that cause similar
> problems).
>
> What it comes down to is fairly simple: by using public derivation,
> you've _promised_ that a derived can be substituted for a base under any
> and all possible circumstances.
That seems false: since the language allows public derivation of classes
without virtual destructor, public inheritance obviously does not _promise_
that a derived class can be substituted for a base under _any_
circumstances. If it did, the standard would require the destructor of a
public base to be virtual. In fact, public inheritance per se does not
promise anything but the behavior guaranteed by the standard. Any claims
and connotations beyond the technical meaning of public inheritance are
part of (local) coding standards and style guides. Those might be more or
less well-founded and lay out best practices, but they do not define a
contract for public inheritance. Most importantly, such guidelines are in
my experience always closely tied to a certain domain or programing
paradigm, e.g., OO. In a given context, they can be perfectly valid.
Presented as universal truths about C++ programming, they turn into
falsehoods rather quickly.
> The problem arises for the simple reason
> that this is a lie -- under at least one circumstance (destruction) the
> substitution leads to undefined behavior.
>
> In short, even though you _can_ get away with this as long as you're
> sufficiently careful about how you use it, it's a lousy idea. Public
> derivation has a specific meaning.
(a) The only universal meaning of public inheritance is the one provided by
the standard, which does not require a virtual destructor.
(b) In certain contexts (e.g., OO) public inheritance can acquire another
meaning, e.g., the principle of substitutability that you outlines above.
Those meanings, however, are context specific.
> Unless you really mean it, you
> shouldn't say it by using public derivation. Public derivation from a
> base class without a virtual dtor asserts a falsehood.
Nope. See for instance std::unary_function or std::iterator. Inheriting
publicly from those classes is perfectly fine and does not assert any
falsehoods. It just happens to be outside the scope of OO design and is
more closely related to generic programming. In that context, public
inheritance from base classes without virtual destructor is quite common
and nobody knowing the corresponding idioms will read public inheritance as
indicating substitutability in all contexts.
Best
Kai-Uwe Bux
Well put. There seem to be two schools of thought: one school emphasizes the
methods of tying the client down so that it cannot go astray; the other
school emphasizes the goal of designing a useful class and accepts that
undefined behavior may result from violating the preconditions of the
specified contract. The STL is an example for the later and, in my opinion,
establishes a precedence: it is at least not totally out of line to use
that approach to class design in C++.
That said, there is almost a continuum of design choices and some are more
hazardous than others. I would not go out of my way to safeguard against
all possible misuses, but I would also not propose a design that requires
each user of the class to read all the fine print to use it for simple
tasks without running into undefined behavior.
In the end, I think, each class should come with a set of recommended idioms
for safe use; and users should know that they have to be careful once they
depart from the recommended idioms and have to read the actual contracts.
Best
Kai-Uwe Bux
[ ... ]
> That seems false: since the language allows public derivation of classes
> without virtual destructor, public inheritance obviously does not _promise_
> that a derived class can be substituted for a base under _any_
> circumstances.
You're takin the fact that something is standardized as meaning there
must be some circumstance under which it should be done, or is
meaningful, etc?
While I'm certainly not going to get into a long discussion over it,
this strikes me as fallacious reasoning. I guess if (for example) you
insist there's a good time to use gets, you can go ahead and do that. I
hope you'll forgive me if I pass. While I'll openly admit this isn't
_as_ dangerous as gets, it's still a bad idea -- there's simply no good
reason to do it. If you're deriving for the sake of convenience, and
don't want to allow (for example) pointers/references to your derived
class to be converted implicitly to pointers/references to the base
class, you have a choice of private or protected inheritance.
[ ... ]
> Well put. There seem to be two schools of thought: one school emphasizes the
> methods of tying the client down so that it cannot go astray; the other
> school emphasizes the goal of designing a useful class and accepts that
> undefined behavior may result from violating the preconditions of the
> specified contract.
Pardon my being blunt, but this is barely short of complete nonsense.
Attempting to write your class in a way that it's reasonably safe isn't
tying the client down.
A design does not have to encourage its clients to shoot themselves in
the feet to be useful.
> In article <eff94t$g3t$1...@murdoch.acc.Virginia.EDU>, jkher...@gmx.net
> says...
>
> [ ... ]
>
>> That seems false: since the language allows public derivation of classes
>> without virtual destructor, public inheritance obviously does not
>> _promise_ that a derived class can be substituted for a base under _any_
>> circumstances.
>
> You're takin the fact that something is standardized as meaning there
> must be some circumstance under which it should be done, or is
> meaningful, etc?
No, you are misconstruing my reasonging: The reference to the standard is
just to establish that there is no basis for your claim that public
inheritance makes the kind of promise you claim it makes.
This is completely independent of whether it can be a good idea to inherit
from classes with non-virtual destructors. That this is, indeed, the case
follows from examples like generic programming with policy classes or such
niceties as std::unary_function.
However, any of that does not mean that it is a good idea to inherit for
convenience from std::vector. But your reasoning was much wider in scope
than this particular case.
> While I'm certainly not going to get into a long discussion over it,
> this strikes me as fallacious reasoning. I guess if (for example) you
> insist there's a good time to use gets, you can go ahead and do that.
I hope the remarks above make it clear that the reasoning runs a little
different. It should be clear, that the my reasoning, understood properly,
does not apply to gets.
> I hope you'll forgive me if I pass. While I'll openly admit this isn't
> _as_ dangerous as gets, it's still a bad idea -- there's simply no good
> reason to do it.
So what about std::iterator and std::unary_function? What about policy
classes as featured in "Modern C++ Design"? There are plenty of good
reasons to publicly inherit from classes that do not have virtual
destructors. Your warning is good advice and firmly rooted in the paradigm
of OO design but does not extend far beyond. It does not apply in other
cases (like generic programming), where such inheritance indeed can be (and
often is) a good idea.
> If you're deriving for the sake of convenience, and
> don't want to allow (for example) pointers/references to your derived
> class to be converted implicitly to pointers/references to the base
> class, you have a choice of private or protected inheritance.
Again, consider std::binary_function and the likes of it. Here, private
inheritance is not an option for the intended use. In these cases, it is
just understood that you do not use std::binary_function<>* polymorphically
(and how/why would you: there are no virtual member functions to begin
with).
Best
Kai-Uwe Bux
> In article <effi92$jo1$1...@murdoch.acc.Virginia.EDU>, jkher...@gmx.net
> says...
>
> [ ... ]
>
>> Well put. There seem to be two schools of thought: one school emphasizes
>> the methods of tying the client down so that it cannot go astray; the
>> other school emphasizes the goal of designing a useful class and accepts
>> that undefined behavior may result from violating the preconditions of
>> the specified contract.
>
> Pardon my being blunt, but this is barely short of complete nonsense.
> Attempting to write your class in a way that it's reasonably safe isn't
> tying the client down.
I think, I did not say that.
In the part you snipped, I cited the STL as an example for the second kind
of design: you get undefined behavior if you violate the contract. Do you
consider std::vector inherently unsafe because of operator[], which gives
you undefined behavior when you are out of bounds? I accept std::vector as
a class that is designed "reasonably safe": within typical idioms (loops
from begin() to end(), from 0 to size()), you get the behavior you expect,
and in cases that depart from there, you should use at().
However, I understand that one could argue that undefined behavior is to be
avoided in library classes, and from that point of view, std::vector is a
failed design. That is the difference between the two schools of though
that I see.
> A design does not have to encourage its clients to shoot themselves in
> the feet to be useful.
I think, I did not say that, either.
Best
Kai-Uwe Bux
And that's about everything you get. If the base class has no virtual
functions, what is the use of this code anyway?
If you don't delete through a pointer to base, there *is* no problem.
> and:
>
> 2) There's absolutely NOTHING you can do in 'derived' to prevent it
> from being used in that fashion (or many similar ones that cause
> similar problems).
There is generally nothing you can do to prevent abuse of your code,
except to document the intended use. "This class is not intended to be
used polymorphically!".
Bo Persson
Yup. Quoting everything from the beginning of your message and
responding to what that part said sure is misleading. So I'll adopt your
tactic, and snip the relevant quotes. Why confuse people with facts?
That's *exactly* what you do. Write the documentation. Explain how your
class is designed to be used. Test your code to be confident that, if
used that way, it works as expected. Then, anyone who uses your class
in a way not supported by your documentation and then complains that it
causes them a problem, doesn't have a leg to stand on.
Gavin Deane