Topic: Defect Report: unary_function and binary_function should have protected nonvirtual destructors


Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 26 Aug 2004 06:55:05 GMT
Raw View
petebecker@acm.org (Pete Becker) writes:

> David Abrahams wrote:
>>
>> I think the prominent operator() works nearly as well with fewer ill
>> effects.
>>
>
> Except for function object types that don't define an operator().

Interesting concept.  Example?

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 26 Aug 2004 19:41:31 GMT
Raw View
petebecker@acm.org (Pete Becker) writes:

> David Abrahams wrote:
>>
>> petebecker@acm.org (Pete Becker) writes:
>>
>> > David Abrahams wrote:
>> >>
>> >> I think the prominent operator() works nearly as well with fewer ill
>> >> effects.
>> >>
>> >
>> > Except for function object types that don't define an operator().
>>
>> Interesting concept.  Example?
>>
>
> A function object that wraps a pointer to function and provides a
> conversion operator that returns the pointer. As we discussed last week
> on the WG21 libraries reflector, this eliminates any forwarding issues,
> because the compiler calls the function directly through the
> pointer.

I thought Peter Dimov had some examples where the implicit conversion
was insufficient?  Whatever; I guess the fact that it works sometimes
is enough to make such function objects possible.

Thanks,
Dave

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Tue, 24 Aug 2004 03:36:34 GMT
Raw View
petebecker@acm.org (Pete Becker) writes:

> David Abrahams wrote:
>>
>> petebecker@acm.org (Pete Becker) writes:
>>
>> > David Abrahams wrote:
>> >>
>> >> petebecker@acm.org (Pete Becker) writes:
>> >>
>> >> Maybe achieving optimal size for composed function objects is not
>> >> important enough to make it part of the guideline, though.
>> >
>> > Stating conclusions rather than explaining them is not very
>> > persuasive.
>>
>> I didn't realize you had misunderstood about the EBO thing.  Above is
>> the first time you gave an indication of not understanding it.
>
> Above is the first time you mentioned it.

http://tinyurl.com/3wlyv

> I'm sure many people reading this thread who had no idea what your
> conclusory statement meant. Always keep your audience in mind.

I always do.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jdibling@computer.org (John Dibling)
Date: Tue, 24 Aug 2004 23:48:12 GMT
Raw View
>  but I also think the benefits of using [binary_function and unary_function] is pretty much nonexistent.

IMO using them does have 1 distinct advantage: the self-documentation
provided by semantic clarity.  Even newer STL programmers can
recognize what the purpose in life is for a class derived from
x_function (e.g., it is used as a functor by some algorithm), and
maintain that code appropriately.

- John


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: David Abrahams <dave@boost-consulting.com>
Date: Sat, 21 Aug 2004 19:39:34 CST
Raw View
petebecker@acm.org (Pete Becker) writes:

> David Abrahams wrote:
>>
>> I would suggest a guideline for novices (and
>> experts, too) that says "don't use std::unary_function or
>> std::binary_function".
>>
>
> That seems a bit extreme. "Don't create pointers to std::unary_function
> or std::binary_function" is somewhat closer, or "Don't delete pointers
> to std::unary_function or std::binary_function" would be more accurate.

Doesn't account for the EBO-suppression problem.  Maybe achieving
optimal size for composed function objects is not important enough to
make it part of the guideline, though.

That said, these templates don't provide much benefit, do they?
There's no real abstraction.  It's hard to remember the argument order
-- explicitly making a result_type typedef (and first_argument_type or
whatever where neccessary) would often be clearer and less
error-prone... and with tr1 bind, result_type is all you'll ever
need.  Pretty soon even that will be history as more compilers
support decltype.


--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: technews@kangaroologic.com ("Jonathan Turkanis")
Date: Sun, 22 Aug 2004 03:45:22 GMT
Raw View
"David Abrahams" <dave@boost-consulting.com> wrote in message
news:uk6vs85ta.fsf@boost-consulting.com...
> petebecker@acm.org (Pete Becker) writes:
>
> > David Abrahams wrote:
> >>
> >> I would suggest a guideline for novices (and
> >> experts, too) that says "don't use std::unary_function or
> >> std::binary_function".
> >>
> >
> > That seems a bit extreme. "Don't create pointers to
std::unary_function
> > or std::binary_function" is somewhat closer, or "Don't delete
pointers
> > to std::unary_function or std::binary_function" would be more
accurate.
>
> Doesn't account for the EBO-suppression problem.  Maybe achieving
> optimal size for composed function objects is not important enough
to
> make it part of the guideline, though.
>
> That said, these templates don't provide much benefit, do they?

I think they are useful to document that you are defining a function
object type. I sometime uses them for this purpose even when I do not
need the member typedefs.

Not the intended use, I realize, but it seems reasonable to me.

Jonathan


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hinnant@metrowerks.com (Howard Hinnant)
Date: Sun, 22 Aug 2004 03:45:34 GMT
Raw View
In article <uk6vs85ta.fsf@boost-consulting.com>,
 David Abrahams <dave@boost-consulting.com> wrote:

> petebecker@acm.org (Pete Becker) writes:
>
> > David Abrahams wrote:
> >>
> >> I would suggest a guideline for novices (and
> >> experts, too) that says "don't use std::unary_function or
> >> std::binary_function".
> >>
> >
> > That seems a bit extreme. "Don't create pointers to std::unary_function
> > or std::binary_function" is somewhat closer, or "Don't delete pointers
> > to std::unary_function or std::binary_function" would be more accurate.
>
> Doesn't account for the EBO-suppression problem.  Maybe achieving
> optimal size for composed function objects is not important enough to
> make it part of the guideline, though.
>
> That said, these templates don't provide much benefit, do they?
> There's no real abstraction.  It's hard to remember the argument order
> -- explicitly making a result_type typedef (and first_argument_type or
> whatever where neccessary) would often be clearer and less
> error-prone... and with tr1 bind, result_type is all you'll ever
> need.  Pretty soon even that will be history as more compilers
> support decltype.

<nod>  And then there's the whole name lookup thing.  Do you want your
type to have namespace std associated with it?  It may be more
complication than it is worth just to inherit a few typedefs.

#include <iterator>  // perhaps included indirectly
#include <functional>

namespace Mine
{

struct my_func
    : public std::unary_function<int, bool>
{
    bool operator ()(int i) {return static_cast<bool>(i);}
    void advance(void* p);
};

void advance(my_func& m, void* p)
{
    m.advance(p);
}

}

int main()
{
    Mine::my_func f;
    int i;
    advance(f, &i);  // Mine::advance intended
}

Error   : 'iterator_category' is not a member of class
'std::iterator_traits<Mine::my_func>'
 (point of instantiation: 'main()')
  (instantiating: 'std::advance<Mine::my_func, int *>(Mine::my_func &,
int *)')
iterator line 582    __advance(i, n, typename
iterator_traits<InputIterator>::iterator_category());

Namespace std is searched for advance overloads only because my_func
chose to implement itself by inheriting from std::unary_function.
Otherwise Mine::advance would have been bound to.

-Howard

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Sun, 22 Aug 2004 04:48:34 GMT
Raw View
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uk6vs85ta.fsf@boost-consulting.com...

| need.  Pretty soon even that will be history as more compilers
| support decltype.

which compilers already support decltype?

br

Thorsten


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: radekg@b-runner.nospam.org (Radoslaw Grzanka)
Date: Sun, 22 Aug 2004 05:15:43 GMT
Raw View
Dnia Fri, 20 Aug 2004 22:50:11 +0000, John Dibling napisa=B3(a):

> On Thu, 19 Aug 2004 14:32:27 +0000 (UTC), Joe Gottman
> <jgottman@carolina.rr.com> wrote:
>=20
>> Therefore, they should be given protected nonvirtual destructors.
>=20
> I disagree.  AFAICT, you propose this for the sole purpose of
> protecting inexperienced C++ programmers from hurting themselves.  I
> don't think this is enough reason to add or change features in the
> language, devoid of any other benefits. =20

Language should protect users from making stupid mistakes. One should not
have to spend so many precious time on finding something that language
could easly forbid.=20

Mind you that even experienced programmers may (and do) make stupid
mistakes.

If there is no negative effects it should be implemented "more safe way"
and it may be considered as language defect.
If there is any use of current implementation it should be left the way i=
t
is now.

Cheers,
  Radoslaw

--=20
"Oceniaj=B1 mnie, cho=E6 nic o mnie nie wiedz=B1. To dlatego jestem sam" =
- Shrek
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D
e-mail: sad[na]rpg[kropka]pl                 JID: radekg[na]chrome[kropka=
]pl
L:C++ E+++ T-- !R P+++ D G++ F:ADoM RL--- !RLA W:CP Q++ AI++ RN+ Hp- Re++=
 S+

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Sun, 22 Aug 2004 19:25:35 GMT
Raw View
nesotto@cs.auc.dk ("Thorsten Ottosen") writes:

> "David Abrahams" <dave@boost-consulting.com> wrote in message news:uk6vs85ta.fsf@boost-consulting.com...
>
> | need.  Pretty soon even that will be history as more compilers
> | support decltype.
>
> which compilers already support decltype?

None that I know of, but for the purpose of building function objects
reference-preserving typeof is good enough, and we can get that on any
compiler that supports typeof (of which there are a few already).

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Mon, 23 Aug 2004 00:49:06 GMT
Raw View
petebecker@acm.org (Pete Becker) writes:

> David Abrahams wrote:
>>
>> petebecker@acm.org (Pete Becker) writes:
>>
>> > David Abrahams wrote:
>> >>
>> >> I would suggest a guideline for novices (and
>> >> experts, too) that says "don't use std::unary_function or
>> >> std::binary_function".
>> >>
>> >
>> > That seems a bit extreme. "Don't create pointers to std::unary_function
>> > or std::binary_function" is somewhat closer, or "Don't delete pointers
>> > to std::unary_function or std::binary_function" would be more accurate.
>>
>> Doesn't account for the EBO-suppression problem.
>
> Huh?
>
>> Maybe achieving optimal size for composed function objects is not
>> important enough to make it part of the guideline, though.
>
> Stating conclusions rather than explaining them is not very
> persuasive.

I didn't realize you had misunderstood about the EBO thing.  Above is
the first time you gave an indication of not understanding it.

If you want to make an optimally-sized compose template, you shouldn't
do something this (omitting many details):

     template <class F1, class F2>
     struct compose
     {
        // ctor omitted

         template <class T>
         F2::result_type operator()(T const& x)
         {
             return f2(f1(x));
         }

         F1 f1;
         F2 f2;
     };

Because even if f1 and f2 have no data members, as is frequently the
case, they will occupy space in the composed function object.

Instead you should do something like:

     template <class F1, class F2>
     struct compose
     {
        // ctor omitted

         template <class T>
         F2::result_type operator()(T const& x)
         {
             return f.second()(f.first()(x));
         }

         boost::compressed_pair<F1,F2> f;
     };

Because compressed_pair will use inheritance from F1 and/or F2 when
possible, to allow the empty base optimization to kick in.
See the compressed_pair docs on the Boost website for details.

If F1 and F2 are both derived from std::unary_function<int,int> (for
example) as is likely, EBO will not kick in because the compiler isn't
allowed to place two instances of the same type at the same address.

>> That said, these templates don't provide much benefit, do they?
>> There's no real abstraction.  It's hard to remember the argument order
>> -- explicitly making a result_type typedef (and first_argument_type or
>> whatever where neccessary) would often be clearer and less
>> error-prone... and with tr1 bind, result_type is all you'll ever
>> need.  Pretty soon even that will be history as more compilers
>> support decltype.
>>
>
> Okay, so your advice is that since other approaches may become
> possible in the future, current approaches should not be used.

No.  My advice is that they should not be used because they provide
little or no benefit, they're hard to use correctly compared to what
little benefit they might provide, and they come with some pitfalls,
among them that some people to waste time worrying about whether they
should have virtual dtors.  It comes up periodically in this NG.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: qrczak@knm.org.pl ("Marcin 'Qrczak' Kowalczyk")
Date: Sat, 21 Aug 2004 03:52:13 GMT
Raw View
On Fri, 20 Aug 2004 22:50:11 +0000, John Dibling wrote:

>> Therefore, they should be given protected nonvirtual destructors.
>
> I disagree.  AFAICT, you propose this for the sole purpose of
> protecting inexperienced C++ programmers from hurting themselves.
> I don't think this is enough reason to add or change features in the
> language, devoid of any other benefits.

Does this change have negative side effects? If not, I don't understand
this attitude.

--
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Sat, 21 Aug 2004 16:37:44 GMT
Raw View
Joe Gottman <jgottman@carolina.rr.com> writes:

> [ note: forwarded to C++ Comittee - sdc ]
>
>    The classes std::unary_function and std::binary_function are both
> designed to be inherited from but contain no virtual functions.  This makes
> it too easy for a novice programmer to write code like
>     binary_function<int, int, int> *p = new plus<int>;
>     delete p;
>
> There are two common ways to prevent this source of undefined behavior: give
> the base class a public virtual destructor, or give it a protected
> nonvirtual destructor.  Since unary_function and binary_function have no
> other virtual functions, (note in particular the absence of an
> operator()() ), it would cost too much to give them public virtual
> destructors.  Therefore, they should be given protected nonvirtual
> destructors.

IMO, forget ever getting this through.  That would impose unacceptable
overhead.  In fact, these templates already do that in many cases by
disabling EBO (consider composing two function objects, using
compressed_pair).  So I would suggest a guideline for novices (and
experts, too) that says "don't use std::unary_function or
std::binary_function".

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: tslettebo@hotmail.com ("Terje Sletteb ")
Date: Sat, 21 Aug 2004 18:18:03 GMT
Raw View
"John Dibling" <jdibling@computer.org> wrote in message
news:74f9i05r1s8cme6e042h358bspedg32hom@4ax.com...
> On Thu, 19 Aug 2004 14:32:27 +0000 (UTC), Joe Gottman
> <jgottman@carolina.rr.com> wrote:
>
> > Therefore, they should be given protected nonvirtual destructors.
>
> I disagree.  AFAICT, you propose this for the sole purpose of
> protecting inexperienced C++ programmers from hurting themselves.  I
> don't think this is enough reason to add or change features in the
> language, devoid of any other benefits.

I find this a strange attitude, given that one of the commonly stated aims
of C++0x is to "make it easier to teach and learn"
(http://cpptips.hyperformix.com/cpptips/c++0x) (first link I found when
googling).

> Does anyone know if any other changes have been made to the laguage to
> protect newbie programmers from themselves?  Did these changes have
> any collateral benefits as well?

As long as they did not have unreasonable negative consequences, I think
removing gotchas is a major advantage in itself.

However, in this case, the absence of a protected destructor seems to be
pretty harmless.

Regards,

Terje


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jdibling@computer.org (John Dibling)
Date: Fri, 20 Aug 2004 22:50:11 GMT
Raw View
On Thu, 19 Aug 2004 14:32:27 +0000 (UTC), Joe Gottman
<jgottman@carolina.rr.com> wrote:

> Therefore, they should be given protected nonvirtual destructors.

I disagree.  AFAICT, you propose this for the sole purpose of
protecting inexperienced C++ programmers from hurting themselves.  I
don't think this is enough reason to add or change features in the
language, devoid of any other benefits.

Does anyone know if any other changes have been made to the laguage to
protect newbie programmers from themselves?  Did these changes have
any collateral benefits as well?

- John

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Mon, 23 Aug 2004 15:51:34 GMT
Raw View
technews@kangaroologic.com ("Jonathan Turkanis") writes:

> "David Abrahams" <dave@boost-consulting.com> wrote...
>> petebecker@acm.org (Pete Becker) writes:
>>
>> > David Abrahams wrote:
>> >>
>> >> I would suggest a guideline for novices (and
>> >> experts, too) that says "don't use std::unary_function or
>> >> std::binary_function".
>> >>
>> >
>> > That seems a bit extreme. "Don't create pointers to std::unary_function
>> > or std::binary_function" is somewhat closer, or "Don't delete pointers
>> > to std::unary_function or std::binary_function" would be more accurate.
>>
>> these templates don't provide much benefit, do they?
>
> I think they are useful to document that you are defining a function
> object type. I sometime uses them for this purpose even when I do not
> need the member typedefs.
>
> Not the intended use, I realize, but it seems reasonable to me.

I think the prominent operator() works nearly as well with fewer ill
effects.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.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.jamesd.demon.co.uk/csc/faq.html                       ]