Topic: Non-virtual destructors & valarray memory allocation


Author: cbarron413@adelphia.net (Carl Barron)
Date: Thu, 15 Jun 2006 14:33:48 GMT
Raw View
In article <1150293764.992142.174700@c74g2000cwc.googlegroups.com>,
Earl Purple <earlpurple@gmail.com> wrote:

>
> A protected destructor isn't the answer though, a virtual one would
> solve the problem. And of course operator() would have to be virtual
> too. So instead you have to write your own version of unary_function
> that does have a virtual destructor. (Does boost's have one?)
>
   boost and tr1 have template <class Sig> class function;

so std::map<key_type,function<A(B)> > should work  Function is
not compareable. But is copyable and assignable.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Sat, 10 Jun 2006 09:45:20 CST
Raw View
Michael Hopkins wrote:
> All I want to do is add one further member function to std::vector<T>. We
> use loops from 1 to n here for their natural fit to mathematical and
> statistical thinking, and will continue to do so.  Changing this would have
> a catastrophic effect in terms of bug creation and headaches when thinking
> about and expressing algorithms and will not happen for that reason.
>
As far as possible extension of an old class should be done by adding
non-member functions.
Unfortunately, operator() can't be written as non-member function.

> Luckily, C++ has ample scope for expressing this in a type that we can use
> exclusively to solve our problem, so we chose the natural solution - a
> member function that apes Fortran behaviour with this.
>
> template <typename T>
> class uo_vec : public std::vector<T>  // for Unit-Offset vector
> {
>   public:
>     T& operator()( const iter i )
>     {
>       return std::vector<T>::operator[](i - 1);
>     }
>   etc..
> };
>
[snip]
>
> Correct me if I'm wrong (I often am with C++), but wouldn't aggregation or
> private inheritance (or any other approach) require the writing of endless
> forwarding functions?
>
With private inheritance + using directives, you can get it right:


template <class T, class Allocator = std::allocator<T> >
class uo_vec : private std::vector<T, Allocator>
{
  typedef std::vector<T, Allocator> Base;
  public:
  using Base::reference; using Base::const_reference;
  using Base::iterator; using Base::const_iterator;
  using Base::size_type; using Base::difference_type; using
Base::value_type;using Base::allocator_type;
  using Base::pointer; using Base::const_pointer;
  using Base::reverse_iterator; using Base::const_reverse_iterator;

  explicit uo_vec(const Allocator& allocator=
Allocator()):Base(allocator) {}
  explicit uo_vec(typename uo_vec::size_type n, const T& value=T(),
const Allocator& allocator = Allocator()):Base(n, value, allocator) {}
  template <class InputIterator>
  uo_vec(InputIterator first, InputIterator last, const Allocator&
allocator = Allocator())
    :Base(first, last, allocator) {}
  // computer generated copy-constructor, copy-assignment operator and
destructor are correct.

  using Base::assign;
  using Base::get_allocator;
  using Base::begin; using Base::end; using Base::rbegin; using
Base::rend;
  using Base::size; using Base::max_size;using Base::resize;
  using Base::capacity; using Base::empty; using Base::reserve;
  using Base::operator[]; using Base::at;
  using Base::front; using Base::back; using Base::push_back; using
Base::pop_back;
  using Base::insert; using Base::erase;
  using Base::clear;
  void swap(uo_vec& other) {swap(other);}

  T& operator()( const typename Base::size_type i )
  {
    return std::vector<T>::operator[](i - 1);
  }
  const T& operator()( const typename uo_vec::size_type i ) const
  {
    return std::vector<T>::operator[](i - 1);
  }
};

I agree, it isn't beautiful... Furthermore, you'll not be able to use
non-member functions that work only on std::vectors, but as far as I
know you don't want that, because you fear that one could delete your
class via a std::vector pointer.

> Anyway, that is the motivation for what we currently use quite successfully,
> but there is always the nagging doubt that something one day will refer to
> it by a base class pointer and then.. Bang.  I would prefer not to have this
> worry.
>
I think that the threat is smaller than you think.
You have to delete, by yourself, all the vectors you create... You only
need to be careful when an old function "takes ownership" of a
std::vector that you have to allocate (for instance, with a
std::auto_ptr<std::vector<int> > sink). In that case, you must be
careful, and pass only a *true* std::vector. But I think that this type
of function/method is seldom.
Calling "delete" on a type which contains a std::vector is not seldom,
but deleting a std::vector from a direct pointer to std::vector is very
unusual.

Note also that fortunately (or unfortunately), deleting a uo_vec from a
std::vector<T>*, causes UB, but this UB is likely, on popular C++
implementations, to do absolutely no harm (i.e. no memory leak, and no
crash).

> It seems to me that some of the (undoubtedly excellent) thinking behind
> giving C++ such increased expressive power over C at so little cost
> efficiency-wise has introduced quite a few subtle bugs and gotchas - so that
> you can become paranoid in case you break some arcane rule. Think of the
> number of style guides and 'gotchas' books that have come out - surely more
> than all other languages put together!
>
Yes, C++ is a complex language, full of traps for beginners &
intermediate programmers.
> What would the practical downside be in giving std::vector & std::valarray
> virtual destructors and deriving from them - two bytes per object?
>
It depends on the architecture... On IA-32, it is more likely to use 4
bytes per object.
It is not negligible. An empty std::vector is likely to use only 12
bytes... 16 bytes is ... 33% more.
And there can be simplier containers (perhaps not STL containers)...
There can be containers using only 4 bytes... In that case, adding 4
bytes double the size of the empty container.
What would be the rationale behind choosing whether a container has a
virtual destructor or not?
Would it be correct to say : std::deque has a virtual destructor
because it is a large complex container, but not boost::array ?

> Doesn't seem like a big disadvantage in these days of Gb of memory and wouldn't the
> tradeoff be nice; guaranteed type-safe behaviour in containers.

Not all machines have Gb of memory... And these Gb of memory might be
full of 50000000 tiny or empty vectors... In that case, 4 bytes per
vector will increase the size by approximatively 200MB.
C++ must also runs on memory-bound machines... With 640KiB of memory,
or less.

Note that, in your example, you only want a virtual destructor in
std::vector for bug prevention (not because you really need it). Do you
think that a bug prevention of a very very small minority of C++
programmers (those who derive from std::vector) worth the cost of
adding 4 bytes to std::vector (even if this cost is not huge, it is a
real cost).

> Question number two was about our need to wrap some C libraries that use
> vectors with a few extra elements to hold coded information about length,
> orientation etc and extract this info with a defined interface - an early
> attempt many years ago to 'objectify' linear algebra objects with C code
> that has actually worked very effectively.
>
> We are now interfacing to these 'objects' and their algorithms with a type
> that uses std::valarray<T>. I would like to be able to use the member
> functions such as min(), max() and others but with some information numbers
> 'tacked on the end' of a single valarray we can't.
>
> This is not a major headache as e.g. looped min() is not always slower than
> member function min() in our tests - it's just about seeing how elegant we
> can make the solution.  If we could guarantee that the _data_content_ of v1
> & v2 below were contiguous (which I suspect we cannot) then we could use v1
> for the extra information and treat v2 exactly as a data vector.  And when
> we need to send it to the C-based functions we could use &v1[0].
>
>     class V {
>         std::valarray<double>  v1, v2;
>     }
>
Even if you could make v1 data contiguous to v2 (perhaps using custom
allocators), that would be a so ugly design that I would recommend any
other alternative.
Seriously, I would never do that!

I can see two main alternatives :
Having the extra information as members of V, well separated from the
v2 data.
class V {
/* meaningful members*/
std::valarray<double> v2;
};

And perhaps, one or two member functions generating C-compatible
representations (probably at the cost of heavy memory copies).
Ideally, a class should hide the underlying memory structure... And its
interface should be independent of this underlying data structure.

Another alternative is to avoid using std::valarray : Simply use a mean
which gives you more power on the underlying memory representation...
Perhaps a single big std::vector, or memory allocated with
new[]/delete[].
The downside of this approach is that you'll not benefit from
std::valarray member functions (yeah, object-based programming means
that you can't reuse functions without using the data structure).
Fortunately, you can still use STL algorithms.
And, if ever, a std::valarray member was so efficient & cool that you
would want to use it at any cost, you can still convert your data
structure to std::valarry, just for the time of doing the operation,
and then, copy back the data from the resulting std::valarray, to your
well-defined data structure.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Sun, 11 Jun 2006 10:28:27 CST
Raw View
* Earl Purple -> Alf P. Steinbach:
>> Sometimes the point of deriving from a class is only to extend.
>>
>> At least one popular language even uses the keyword "extends" to
>> designate class derivation.
>
> That popular language also has every class deriving from an Object
> class, and doesn't have destructors at all, so no need to worry about
> virtual ones. Nor does it support free-functions although you can
> create a class simply to provide functions. It does have a "final"
> keyword though.

Now you're really bad-mouthing Eiffel...


[snip]
>
> constructors: Easy. Suppose I want to be able to create a vector from a
> static array. Let's create a function make_vector.
>
> template < typename T, size_t N >
> std::vector< T > make_vector( const T (&arr)[N] )
> {
>    return std::vector( arr, arr+N );
> }
>
> std::vector< int > = make_vector( { 1, 2, 3, 4, 5 } );
>
> (I think that should compile anyway)

There are some differences regarding both efficiency and functionality.


[snip]
>
>> Some standard library classes have protected members.
>
> Some standard library classes are meant to be derived from like
> basic_streambuf. Are there any that have protected members and no
> virtual methods and no virtual destructor?

std::binder1st (   20.3.6.1)
std::binder2nd (   20.3.6.3)
std::queue (   23.2.3.1)
std::priority_queue (   23.2.3.2)
std::stack (   23.2.3.3)
std::map (   23.3.1/2)
std::multimap (   23.3.2/2)
std::reverse_iterator (   24.4.1.1)
std::back_insert_iterator (   24.4.2.1)
std::front_insert_iterator (   24.4.2.3)
std::insert_iterator (   24.4.2.5)
std::ios_base (   27.4.2)
std::basic_ios (   27.4.4)

And maybe more.


[snip]
> Is there a standard policy with regards to the behaviour of
> tr1::shared_ptr deleters? If so, what is it?

Not sure, but a deleter is rather useless if it isn't propagated when
the smart-pointer is copied.


>> Summing up, when deriving from a standard library class would be in
>> order except for the lack of virtual destructor, just derive, but don't
>> destroy polymorphically  --  use smart pointers if that's an issue.
>
> Yes obviously. But it is probably still wrong to derive from concrete
> classes most of the time.

Well, I see no technical reason.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Wed, 14 Jun 2006 09:35:17 CST
Raw View
kanze wrote:
> While it might be marginally
> safer if std::unary_function had a protected destructor, I don't
> find this to be a problem in real code -- programmers just don't
> have std::unary_function*, period, much less delete them.

So you would never want to do this then:

- Have a look-up table, either vector or map from a key to a (typed,
obviously) unary_function
- Look-up and invoke a unary function based on runtime information

Now you can do that now, but you can't use something like shared_ptr<
unary_function< A, B > > (where A and B are your types) in your
vector/map. Instead you would have to take care of the memory
management of each function (or have them as globals somewhere, which
may be inappropriate).

>And
> of course, if std::unary_function did have a protected
> destructor, then classes derived from it could never be members
> of a union.

A protected destructor isn't the answer though, a virtual one would
solve the problem. And of course operator() would have to be virtual
too. So instead you have to write your own version of unary_function
that does have a virtual destructor. (Does boost's have one?)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: bop@gmb.dk ("Bo Persson")
Date: Wed, 7 Jun 2006 18:34:18 GMT
Raw View
"John Nagle" <nagle@animats.com> skrev i meddelandet
news:Q_Dhg.40871$fb2.32505@newssvr27.news.prodigy.net...
> Michael Hopkins wrote:
>> 1) Why were the std:: library containers not given virtual
>> destructors - is
>> this a feature or an oversight?
>
>    I didn't know that.
>
>    It's one of those things that reminds you that allowing a derived
> class
> with a destructor from one with a non-virtual destructor was a
> really
> dumb language design decision.
>

No, it's not. It's an example of "you don't pay for what you don't
use" principle.

You run into problems *only* if you delete an object of a derived
class thru a pointer to base. I never do that, but I derive classes
all the time!

If you need a virtual destructor, you define one, if you don't -
don't.


In this particular case, if the OP derives from std::vector to extend
some functionality, he should probably not access his derived objects
thru a pointer to vector. That would be pretty useless anyway, as he
then couldn't access the extensions.


Bo Persson


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: stephen.clamage@sun.com (Steve Clamage)
Date: Wed, 7 Jun 2006 19:56:00 GMT
Raw View
Michael Hopkins wrote:
>
> 1) Why were the std:: library containers not given virtual destructors - is
> this a feature or an oversight?  If the latter, I wonder if it would be
> something that could be changed easily in the upcoming standard without
> breaking current code.

The containers were deliberately designed not to support run-time
polymorphism. They are intended NOT to be derived from. The reason is to
support efficient implementation based on compile-time polymorphism.

You can use a container type as a member of class that has different or
additional features.

>
> We would like to derive publicly from them in a couple of cases and now have
> to be more disciplined than we should need to be about how we use those
> types.

Deriving from non-polymorphic classes is a Bad Idea.

It might help to explain what problem you need to solve. You have
presented a proposed solution: "Derive from standard containers." Back
up a few steps. Another approach might be better.

>
>
> 2) Is there any way of declaring e.g. two valarray<double> so that they are
> guaranteed to be contiguous in memory? i.e.
>
>     class V {
>         std::valarray<double>  v1, v2;
>     }
>

The v2 member must always follow v1 in this example, but you can't
always predict whether additional padding might be present. It is never
valid to use an address outside the bounds of a single object. That is,
if you try to access sizeof(v1) bytes beyond v1, the results are undefined.

In an array of type T, the members are always at consecutive multiples
of sizeof(T) bytes, by definition.  Since the array itself is one
object, you can compute the addresses of individual members. Maybe that
will help.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alec@arlross.demon.co.uk (Alec Ross)
Date: Wed, 7 Jun 2006 20:21:45 GMT
Raw View
This is a MIME message

--=_Turnpike_VtYh3qFq8yhEF+M2=
Content-Type: text/plain;charset=us-ascii;format=flowed

{Note to mods.  I would prefer to have my last post amended to quote
MEffC++, rather than MEC++, as I just posted.  Appologies, and TIA.}

   ------- Forwarded message follows -------

--=_Turnpike_VtYh3qFq8yhEF+M2=
Content-Type: message/rfc822

Message-ID: <Xt8h3LF62yhEFwDn@arlross.demon.co.uk>
Date: Wed, 7 Jun 2006 20:49:14 +0100
From: Alec Ross <alec@arlross.demon.co.uk>
Newsgroups: comp.std.c++
Subject: Re: Non-virtual destructors & valarray memory allocation
Path: arlross.demon.co.uk!alec
References: <C0AC4A1F.16336%michael.hopkins@hopkins-research.com>
 <Q_Dhg.40871$fb2.32505@newssvr27.news.prodigy.net>
Lines: 19
MIME-Version: 1.0
Content-Type: text/plain;charset=us-ascii;format=flowed
User-Agent: Turnpike/6.02-S (<pukOvvr2v03xuXmaOrS2FtDqKy>)
To: comp-std-c++@moderators.isc.org

In message <Q_Dhg.40871$fb2.32505@newssvr27.news.prodigy.net>, John
Nagle <nagle@animats.com> writes
>Michael Hopkins wrote:
>> 1) Why were the std:: library containers not given virtual destructors - is
>> this a feature or an oversight?
>
>   I didn't know that.
>
>   It's one of those things that reminds you that allowing a derived class
>with a destructor from one with a non-virtual destructor was a really
>dumb language design decision.

I disagree.  I'm with the view expressed in, e.g. MEC++:

"All base class destructors should be either virtual and pubic, or
non-virtual and protected."  (p 168)

--
Alec Ross

--=_Turnpike_VtYh3qFq8yhEF+M2=
Content-Type: text/plain;charset=us-ascii;format=flowed


--
Alec Ross

--=_Turnpike_VtYh3qFq8yhEF+M2=--

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alfps@start.no ("Alf P. Steinbach")
Date: Wed, 7 Jun 2006 23:57:07 GMT
Raw View
* Earl Purple:
> Michael Hopkins wrote:
>> Hi all
>>
>> A couple of questions that are influencing the design of some classes.
>>
>>
>> 1) Why were the std:: library containers not given virtual destructors - is
>> this a feature or an oversight?
>
> Feature. They don't need them as they have no other virtual methods so
> how can you override any of their functionality anyway?

Sometimes the point of deriving from a class is only to extend.

At least one popular language even uses the keyword "extends" to
designate class derivation.

That said the lack of virtual destructors is only a problem if
dynamically allocated instances are destroyed polymorphically, which in
practice isn't much of a problem, especially compared to the much larger
& more serious other pitfalls one may stumble into when using C++.


>> We would like to derive publicly from them in a couple of cases and now have
>> to be more disciplined than we should need to be about how we use those
>> types.
>
> There is no need to derive publicly from them. If you want to add extra
> functionality then either:
>
> 1. create free-functions that take the collections as parameters

Consider constructors, notational consistency, introduction of virtual
member functions, interfaces, memory management, you name it.


> After all, you are only going to use their public methods (there are no
> protected ones and you won't have access to the private ones anyway).

Some standard library classes have protected members.


> 2. Create a class that uses aggregation, i.e. it contains the
> collection you want and has extra functions. You can then allow users
> to call all the original functions either by implementing them
> yourself, providing an implicit conversion or (preferred) overloading
> operator-> (operator. cannot be overloaded). The last of these will
> automatically bring in all the behaviour you want without the dangers
> of implicit conversion.

Consider e.g. downcasting.

Regarding the destruction issue, what are smart pointers for?
Essentially a smart pointer puts in place, or can put in place, the
equivalent of a virtual destructor.

Summing up, when deriving from a standard library class would be in
order except for the lack of virtual destructor, just derive, but don't
destroy polymorphically  --  use smart pointers if that's an issue.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alec@arlross.demon.co.uk (Alec Ross)
Date: Thu, 8 Jun 2006 03:13:56 GMT
Raw View
In message <Q_Dhg.40871$fb2.32505@newssvr27.news.prodigy.net>, John
Nagle <nagle@animats.com> writes
>Michael Hopkins wrote:
>> 1) Why were the std:: library containers not given virtual destructors - is
>> this a feature or an oversight?
>
>   I didn't know that.
>
>   It's one of those things that reminds you that allowing a derived class
>with a destructor from one with a non-virtual destructor was a really
>dumb language design decision.

I disagree.  I'm with the view expressed in, e.g. MEC++:

"All base class destructors should be either virtual and pubic, or
non-virtual and protected."  (p 168)

--
Alec Ross

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Wed, 7 Jun 2006 22:13:58 CST
Raw View
Alec Ross wrote:
>
> I disagree.  I'm with the view expressed in, e.g. MEC++:
>
> "All base class destructors should be either virtual and pubic, or
> non-virtual and protected."  (p 168)
>
And how could you use std::vector?
I mean that:

auto std::vector<int> v; // would do a compile-time error saying that
the destructor is not accessible.

For *abstract* classes (or classes which are conceptually abstract
enough, so it doesn't make sense to create instances of them) it can be
a good guideline.

Anyway if you want a "new improved" vector class having a virtual
destructor, that's very easy:

template <class T>
class MyImprovedVector:public std::vector<T>
{
  public:
  virtual ~MyImprovedVector() {}
};

Now if you think that it makes sense to manipulate a derived object via
a pointer to MyImprovedVector (knowing that you can't do anything
polymorphic on that, because a vector has no virtual methods) you
can... Actually you can even do a polymorphic operation on that (and
only one) : Destruction.
In fact, you can also do RTTI and ugly dynamic_casts... But that's
probably the only mean that allow to really "use" your objects from a
base class pointer.

Note also that deriving publicily from a concrete class is usually a
sign of design flaw... And all STL containers are very concrete
classes.
Deriving publicily from them is worse (from an encapsulation
point-of-view) than having a public member being an STL container.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Nevin \":-]\" Liber" <nevin@eviloverlord.com>
Date: Thu, 8 Jun 2006 08:25:19 CST
Raw View
In article <Q_Dhg.40871$fb2.32505@newssvr27.news.prodigy.net>,
 nagle@animats.com (John Nagle) wrote:

>     It's one of those things that reminds you that allowing a derived class
> with a destructor from one with a non-virtual destructor was a really
> dumb language design decision.

What other member functions of a collection should be virtual?  All of
them?

After all, if you are advocating polymorphic behavior, there really
ought to be some functionality you are expecting to override...

--
 Nevin ":-)" Liber  <mailto:nevin@eviloverlord.com>  (773) 961-1620

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alec@arlross.demon.co.uk (Alec Ross)
Date: Thu, 8 Jun 2006 13:25:27 GMT
Raw View
In message <1149716872.436529.306660@y43g2000cwc.googlegroups.com>,
SuperKoko <tabkannaz@yahoo.fr> writes
>
>Alec Ross wrote:
>>
>> I disagree.  I'm with the view expressed in, e.g. MEC++:
>>
>> "All base class destructors should be either virtual and pubic, or
>> non-virtual and protected."  (p 168)
>>
>And how could you use std::vector?
>I mean that:
>
>auto std::vector<int> v; // would do a compile-time error saying that
>the destructor is not accessible.
>
Indeed: with a protected dtor, construction of an automatic or static
instance is banned.

The point of the technique is, of course, to:
       - give a compile-time check against deletion using a base class
pointer, protecting against UB
       - not requiring a virtual dtor in the base class.  This could
avoid the overheads of e.g.a vtable, if the dtor would have been the
only virtual function in the base.  (And, even if there were other
virtual function, it could at least avoid any additional indirection
penalties for the dtor calls.)

If it were indeed required to have auto and/or static instances, then
the protected dtor option would be ruled out.

>For *abstract* classes (or classes which are conceptually abstract
>enough, so it doesn't make sense to create instances of them) it can be
>a good guideline.
>
Quite.

>Anyway if you want a "new improved" vector class having a virtual
>destructor, that's very easy:
>
>template <class T>
>class MyImprovedVector:public std::vector<T>
>{
>  public:
>  virtual ~MyImprovedVector() {}
>};
>
>Now if you think that it makes sense to manipulate a derived object via
>a pointer to MyImprovedVector (knowing that you can't do anything
>polymorphic on that, because a vector has no virtual methods) you
>can... Actually you can even do a polymorphic operation on that (and
>only one) : Destruction.
>In fact, you can also do RTTI and ugly dynamic_casts... But that's
>probably the only mean that allow to really "use" your objects from a
>base class pointer.
>
>Note also that deriving publicily from a concrete class is usually a
>sign of design flaw... And all STL containers are very concrete
>classes.
Quite.

And, as already mentioned, the STL containers are not intended to be
used as base classes.  The use of non-virtual dtors indicates this.

>Deriving publicily from them is worse (from an encapsulation
>point-of-view) than having a public member being an STL container.
>
No argument here.  (It may be worth mentioning that such a private
member is, of course, OK.)

[Incidentally, apart from possibly the STL design aspect, this thread
now seems to me to be OT here,  and if continued, it should be on
c.l.c++.m IMHO.]

--
Alec Ross

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 8 Jun 2006 08:39:26 CST
Raw View
John Nagle wrote:
> Michael Hopkins wrote:
> > 1) Why were the std:: library containers not given virtual
> > destructors - is this a feature or an oversight?

>     I didn't know that.

>     It's one of those things that reminds you that allowing a
> derived class with a destructor from one with a non-virtual
> destructor was a really dumb language design decision.

Nonsense.  I do it all the time, and I'm not alone.  There are
even examples of it in the standard: std::iterator,
std::unary_function, etc.

If you want to cover all bets, of course, the base class
destructor should be protected.  But in general, the very
semantics of the class are such that it doesn't cause problems.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Thu, 8 Jun 2006 08:40:30 CST
Raw View
Steve Clamage wrote:
> Michael Hopkins wrote:

> > 1) Why were the std:: library containers not given virtual
> > destructors - is this a feature or an oversight?  If the
> > latter, I wonder if it would be something that could be
> > changed easily in the upcoming standard without breaking
> > current code.

> The containers were deliberately designed not to support
> run-time polymorphism. They are intended NOT to be derived
> from. The reason is to support efficient implementation based
> on compile-time polymorphism.

One doesn't necessarily exclude the other; Barton and Nackman
have shown how to support run-time polymorphism AND be very
efficient (as efficient as the STL, at any rate) in cases where
the actual type is know.

> You can use a container type as a member of class that has
> different or additional features.

> > We would like to derive publicly from them in a couple of
> > cases and now have to be more disciplined than we should
> > need to be about how we use those types.

> Deriving from non-polymorphic classes is a Bad Idea.

Do you mean non-polymorphic classes like std::iterator<>, or
std::unary_function? :-)

The problem is, I think, that the C++ language feature of
derivation can be used for several different design features --
OO inheritance is just one.  When the C++ language feature is
used to implement OO inheritance, then the base class must have
a virtual destructor; in fact, the base class must be designed
to support this use.  But when the language feature is used for
other reasons, other rules apply.  While it might be marginally
safer if std::unary_function had a protected destructor, I don't
find this to be a problem in real code -- programmers just don't
have std::unary_function*, period, much less delete them.  And
of course, if std::unary_function did have a protected
destructor, then classes derived from it could never be members
of a union.  (I think that Francis has a proposal under
consideration for explicitly declaring that we want the default
semantics.  Maybe this could be used to declare a protected
destructor without the destructor becoming non-trivial.)

Having said all this, I'm still very sceptical about deriving
from std::vector.  It wasn't designed to be used as an OO base
class -- that's for sure.  But I don't think it was designed to
be used as some other type of base class, either.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Thu, 8 Jun 2006 09:59:15 CST
Raw View
> Sometimes the point of deriving from a class is only to extend.
>
> At least one popular language even uses the keyword "extends" to
> designate class derivation.

That popular language also has every class deriving from an Object
class, and doesn't have destructors at all, so no need to worry about
virtual ones. Nor does it support free-functions although you can
create a class simply to provide functions. It does have a "final"
keyword though.

> That said the lack of virtual destructors is only a problem if
> dynamically allocated instances are destroyed polymorphically, which in
> practice isn't much of a problem,

Probably not with string or vector, possibly more of a problem with
map, but you can't be sure.

> Consider constructors, notational consistency, introduction of virtual
> member functions, interfaces, memory management, you name it.

constructors: Easy. Suppose I want to be able to create a vector from a
static array. Let's create a function make_vector.

template < typename T, size_t N >
std::vector< T > make_vector( const T (&arr)[N] )
{
   return std::vector( arr, arr+N );
}

std::vector< int > = make_vector( { 1, 2, 3, 4, 5 } );

(I think that should compile anyway)

notional consistency: as I've created a vector and not a different
class I have all the functionality of vector.

Ok, I don't have any polymorphism here - if I'm going down that path
and creating a big hierarchy, then I will create a class that contains
a vector and possibly allow some methods like push_back(), begin(),
end(), empty() and size().

> Some standard library classes have protected members.

Some standard library classes are meant to be derived from like
basic_streambuf. Are there any that have protected members and no
virtual methods and no virtual destructor?

> Regarding the destruction issue, what are smart pointers for?
> Essentially a smart pointer puts in place, or can put in place, the
> equivalent of a virtual destructor.

Ok, let's see how. You have an API that takes shared_ptr< map< X , Y >
> but I don't have a map, I have a class derived from map. So I have to stick in some deleter, I presume. I'm not that familiar with the inner workings of boost deleter and what happens to it when you cast. (If the deleter derives from an "untyped" base (untyped on pointer type) and stores the pointer it is going to delete until the time comes then obviously it is simple enough. If the standard deleter does that I don't even need a custom one).

Is there a standard policy with regards to the behaviour of
tr1::shared_ptr deleters? If so, what is it?

> Summing up, when deriving from a standard library class would be in
> order except for the lack of virtual destructor, just derive, but don't
> destroy polymorphically  --  use smart pointers if that's an issue.

Yes obviously. But it is probably still wrong to derive from concrete
classes most of the time.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: rogero@howzatt.demon.co.uk ("Roger Orr")
Date: Thu, 8 Jun 2006 20:40:05 GMT
Raw View
"Michael Hopkins" <michael.hopkins@hopkins-research.com> wrote in message
news:C0AC4A1F.16336%michael.hopkins@hopkins-research.com...
>
>
> Hi all
>
> A couple of questions that are influencing the design of some classes.
>
>
> 1) Why were the std:: library containers not given virtual destructors -
is
> this a feature or an oversight?  If the latter, I wonder if it would be
> something that could be changed easily in the upcoming standard without
> breaking current code.
>
> We would like to derive publicly from them in a couple of cases and now
have
> to be more disciplined than we should need to be about how we use those
> types.

In curious: _why_ do you need to derive publicly?
It's not as if there's any runtime polymorphism available.

Can you can derive privately and expose the methods you need?

Roger Orr
--
MVP in C++ at www.brainbench.com


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Michael Hopkins <michael.hopkins@hopkins-research.com>
Date: Thu, 8 Jun 2006 20:55:35 CST
Raw View

Thanks to all for their comments on my original post (over on comp.std.c++ -
I'm not sure if they arrived on comp.lang.c++).

On the first point - many people have suggested composition (or private
inheritance).

All I want to do is add one further member function to std::vector<T>. We
use loops from 1 to n here for their natural fit to mathematical and
statistical thinking, and will continue to do so.  Changing this would have
a catastrophic effect in terms of bug creation and headaches when thinking
about and expressing algorithms and will not happen for that reason.

Luckily, C++ has ample scope for expressing this in a type that we can use
exclusively to solve our problem, so we chose the natural solution - a
member function that apes Fortran behaviour with this.

template <typename T>
class uo_vec : public std::vector<T>  // for Unit-Offset vector
{
  public:
    T& operator()( const iter i )
    {
      return std::vector<T>::operator[](i - 1);
    }
  etc..
};

This is also self-documenting when used in code so that people will not
think [0..n-1] when they mean (1..n).  It also extends naturally to the
matrix and tensor cases ( i, j ) and ( i, j, k ).  Perfect!

So with this in mind I want something that behaves like a vector in all
other ways - in particular that the standard library algorithms and
containers will treat exactly like a std::vector<T>.

Correct me if I'm wrong (I often am with C++), but wouldn't aggregation or
private inheritance (or any other approach) require the writing of endless
forwarding functions?  And doesn't public inheritance give me exactly what I
need immediately?  (And isn't that one of the main reasons for OOD?)
Anyway, that is the motivation for what we currently use quite successfully,
but there is always the nagging doubt that something one day will refer to
it by a base class pointer and then.. Bang.  I would prefer not to have this
worry.

It seems to me that some of the (undoubtedly excellent) thinking behind
giving C++ such increased expressive power over C at so little cost
efficiency-wise has introduced quite a few subtle bugs and gotchas - so that
you can become paranoid in case you break some arcane rule. Think of the
number of style guides and 'gotchas' books that have come out - surely more
than all other languages put together!

What would the practical downside be in giving std::vector & std::valarray
virtual destructors and deriving from them - two bytes per object?  Doesn't
seem like a big disadvantage in these days of Gb of memory and wouldn't the
tradeoff be nice; guaranteed type-safe behaviour in containers.  Maybe there
are other design decisions that would have allowed e.g. the avoidance of
schizophrenic polymorphism/'slicing' and other unpleasant C++ artefacts -
maybe again at the cost of a few bytes per object.

In engineering generally there has been a strong drive for many years to
design products that are inherently robust against manufacturing,
environment and usage. I don't think anyone could say that about C++ in the
sense of expressing and implementing designs, however enthusiastic they
would rightly be about the complex concepts and algorithms that it is
capable of capturing with such good efficiency.  This is a little surprising
when you think of the care that BS took in terms of static type-checking to
produce exactly that result.

Anyway, enough of that.

Question number two was about our need to wrap some C libraries that use
vectors with a few extra elements to hold coded information about length,
orientation etc and extract this info with a defined interface - an early
attempt many years ago to 'objectify' linear algebra objects with C code
that has actually worked very effectively.

We are now interfacing to these 'objects' and their algorithms with a type
that uses std::valarray<T>. I would like to be able to use the member
functions such as min(), max() and others but with some information numbers
'tacked on the end' of a single valarray we can't.

This is not a major headache as e.g. looped min() is not always slower than
member function min() in our tests - it's just about seeing how elegant we
can make the solution.  If we could guarantee that the _data_content_ of v1
& v2 below were contiguous (which I suspect we cannot) then we could use v1
for the extra information and treat v2 exactly as a data vector.  And when
we need to send it to the C-based functions we could use &v1[0].

    class V {
        std::valarray<double>  v1, v2;
    }


Michael


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

        _/    _/   _/_/_/             Hopkins Research Ltd
       _/    _/   _/    _/
      _/_/_/_/   _/_/_/          http://www.hopkins-research.com/
     _/    _/   _/   _/
    _/    _/   _/     _/               'touch the future'

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: michael.hopkins@hopkins-research.com (Michael Hopkins)
Date: Wed, 7 Jun 2006 15:01:33 GMT
Raw View

Hi all

A couple of questions that are influencing the design of some classes.


1) Why were the std:: library containers not given virtual destructors - is
this a feature or an oversight?  If the latter, I wonder if it would be
something that could be changed easily in the upcoming standard without
breaking current code.

We would like to derive publicly from them in a couple of cases and now have
to be more disciplined than we should need to be about how we use those
types.


2) Is there any way of declaring e.g. two valarray<double> so that they are
guaranteed to be contiguous in memory? i.e.

    class V {
        std::valarray<double>  v1, v2;
    }


TIA and please CC replies to this address

Michael


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

        _/    _/   _/_/_/             Hopkins Research Ltd
       _/    _/   _/    _/
      _/_/_/_/   _/_/_/          http://www.hopkins-research.com/
     _/    _/   _/   _/
    _/    _/   _/     _/               'touch the future'

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alec@arlross.demon.co.uk (Alec Ross)
Date: Wed, 7 Jun 2006 17:19:51 GMT
Raw View
In message <C0AC4A1F.16336%michael.hopkins@hopkins-research.com>,
Michael Hopkins <michael.hopkins@hopkins-research.com> writes
>
>
>Hi all
>
>A couple of questions that are influencing the design of some classes.
>
>
>1) Why were the std:: library containers not given virtual destructors - is
>this a feature or an oversight?  If the latter, I wonder if it would be
>something that could be changed easily in the upcoming standard without
>breaking current code.
>
>We would like to derive publicly from them in a couple of cases and now have
>to be more disciplined than we should need to be about how we use those
>types.
>
I guess that the answer is that they - i.e. instantiations of them -
were not intended to be used as base classes.  See e.g. the second
bullet under STL Design in:

http://en.wikipedia.org/wiki/Standard_Template_Library

Would using a std::container as a data member - i.e. composition - not
be a more acceptable alternative for your purposes?

>
>2) Is there any way of declaring e.g. two valarray<double> so that they are
>guaranteed to be contiguous in memory? i.e.
>
>    class V {
>        std::valarray<double>  v1, v2;
>    }
>
Would using a two element array of the valarrays be acceptable?

HTH

>
>TIA and please CC replies to this address
>
>Michael
>
>
>_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
>
>        _/    _/   _/_/_/             Hopkins Research Ltd
>       _/    _/   _/    _/
>      _/_/_/_/   _/_/_/          http://www.hopkins-research.com/
>     _/    _/   _/   _/
>    _/    _/   _/     _/               'touch the future'
>
>_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
>
>
>---
>[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
>[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
>[              --- Please see the FAQ before posting. ---               ]
>[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]
>

--
Alec Ross

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: nagle@animats.com (John Nagle)
Date: Wed, 7 Jun 2006 18:03:45 GMT
Raw View
Michael Hopkins wrote:
> 1) Why were the std:: library containers not given virtual destructors - is
> this a feature or an oversight?

    I didn't know that.

    It's one of those things that reminds you that allowing a derived class
with a destructor from one with a non-virtual destructor was a really
dumb language design decision.

    John Nagle

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Wed, 7 Jun 2006 13:03:49 CST
Raw View
Michael Hopkins wrote:
> Hi all
>
> A couple of questions that are influencing the design of some classes.
>
>
> 1) Why were the std:: library containers not given virtual destructors - is
> this a feature or an oversight?

Feature. They don't need them as they have no other virtual methods so
how can you override any of their functionality anyway?

> We would like to derive publicly from them in a couple of cases and now have
> to be more disciplined than we should need to be about how we use those
> types.

There is no need to derive publicly from them. If you want to add extra
functionality then either:

1. create free-functions that take the collections as parameters After
all, you are only going to use their public methods (there are no
protected ones and you won't have access to the private ones anyway).

2. Create a class that uses aggregation, i.e. it contains the
collection you want and has extra functions. You can then allow users
to call all the original functions either by implementing them
yourself, providing an implicit conversion or (preferred) overloading
operator-> (operator. cannot be overloaded). The last of these will
automatically bring in all the behaviour you want without the dangers
of implicit conversion.


> 2) Is there any way of declaring e.g. two valarray<double> so that they are
> guaranteed to be contiguous in memory? i.e.
>
>     class V {
>         std::valarray<double>  v1, v2;
>     }

class V
{
 std::valarray<double> v[2];
}

The two valarrays will be in contiguous memory. That doesn't mean the
values they represent will be. They almost certainly won't be. If that
is what you want then no - you'll have to copy them into a big valarray
and then slice it to create the 2 smaller ones (well the 2 slices
anyway).
>
> TIA and please CC replies to this address

No., If you don't have time to read the group, the group doesn't have
time for you either.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]