Topic: Proposed change to rule on deletion through a base class pointer


Author: Dan Smart <cppdan@dansmart.com>
Date: Tue, 28 May 2002 00:42:04 GMT
Raw View
Allan_W@my-dejanews.com (Allan W) wrote in
news:23b84d65.0205211744.64a7cc53@posting.google.com:
>> I thought that overloading the dot operator was avoided since it
>> could cause confusion.
>>
>> Say struct B also has func1().  Which func1() does the following code
>> call?
>>
>> B b;
>> b.func1();
>>
>> My argument may seem a little contrived.
>
> Doesn't look the least bit contrived to me... it seems like if a
> class has an operator.(), it can't have ANY other member functions!
> ...or else, we need to have some way to know what comes after the
> dot, so that we can "return this" for member functions, and return
> something else for other members...
>
Not at all, the compiler knows, therefore either of the following two rules
would work just fine (my preference would be for the second):
1) a.b() uses operator.() always, you can always access A::b() by doing
(&a)->b() or even a.*(A::b)()
2) a.b() uses operator.() if and only if a does not contain a member
function b().

>> But think about smart
>> pointers.  Most smart pointers I have seen do have functions that may
>> be accessed using the dot operator.  If the dot operator is allowed
>> to be overloaded, what would the precedence rules be?  Would
>> B::func1() come before A::func1() or vice versa.  Or would we have to
>> write code like b.A::func1() and b.B::func1()?
Only if your interfaces were really badly designed, which is always going
to be a problem...
>
> It looks to me like this is a fatal flaw in overloading operator.()
>
I disagree, either of the above solutions would seem better to me than not
allowing overloading operator.(), absence of which I consider a minor (but
occasionally extremely irritating) wart.

Dan
--
Dan Smart. C++ Programming and Mentoring.
cppdan@dansmart.com
ADDvantaged

---
[ 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: Allan_W@my-dejanews.com (Allan W)
Date: Wed, 22 May 2002 16:09:21 CST
Raw View
Adin Hunter Baber <mjolnir_DELETE_@soltec.net> wrote
>  Steve Heller <steve@steveheller.com> wrote:
> > Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> > >being able to overload the dot operator would make this so much more
> > >elegant.
> >
> >   Yes, it certainly would! Is that under consideration? If so, it gets
> > my vote.
>
> I thought that overloading the dot operator was avoided since it could
> cause confusion.
>
> Say struct B also has func1().  Which func1() does the following code
> call?
>
> B b;
> b.func1();
>
> My argument may seem a little contrived.

Doesn't look the least bit contrived to me... it seems like if a
class has an operator.(), it can't have ANY other member functions!
...or else, we need to have some way to know what comes after the
dot, so that we can "return this" for member functions, and return
something else for other members...

> But think about smart
> pointers.  Most smart pointers I have seen do have functions that may be
> accessed using the dot operator.  If the dot operator is allowed to be
> overloaded, what would the precedence rules be?  Would B::func1() come
> before A::func1() or vice versa.  Or would we have to write code like
> b.A::func1() and b.B::func1()?

It looks to me like this is a fatal flaw in overloading operator.()

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Tue, 14 May 2002 22:43:43 GMT
Raw View
Hyman Rosen <hyrosen@mail.com> wrote:

>Steve Heller wrote:
>> If the dynamic type does not contain data members that are not present
>> in the static type, and the static type does not have a virtual
>> constructor, the behavior is identical to the behavior of deleting an
>> object of the static type.
>
>I assume the above should say "virtual *de*structor".
>I believe this proposal has no merit and would seriously
>constrain implementations (perhaps as far as making
>certain constructs unimplementable).
>
>For one thing, it completely breaks the case of the derived
>class having its own new and delete operators.
>
>Here's an example where you have layout problems.
>
>struct vb { virtual void f() { } };
>struct base { };
>struct derived : vb, base { };
>base *bp = new derived;
>delete bp;
>
>At the very least, your proposal would force the placement
>of the base part of a derived object at zero offset, which
>is very likely unacceptable.

  Ok, then restrict it to the case where the derived class doesn't
define its own new and delete operators or multiple inheritance.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Tue, 14 May 2002 22:43:34 GMT
Raw View
Michiel.Salters@cmg.nl (Michiel Salters) wrote:

>Steve Heller <steve@steveheller.com> wrote in message news:<tdkqduggvj3ghne9pgecnkg3i8mgaju2mq@4ax.com>...
>> This is a request to the standards committee to change paragraph
>> 5.3.5.3 of the C++ standard from the following:
>>
>> >3 In the first alternative (delete object), if the static type of the op
>>  erand is different from its dynamic type, the
>> >static type shall be a base class of the operand?s dynamic type and th
>>  e static type shall have a virtual
>> >destructor or the behavior is undefined. In the second alternative (dele
>>  te array) if the dynamic type of the
>> >object to be deleted differs from its static type, the behavior is undef
>> ined.
>>
>> to the following:
>>
>>
>> >3 In the first alternative (delete object), if the static type of the op
>> erand is different from its dynamic type, the
>> static type shall be a base class of the operand?s dynamic type or the
>> behavior is undefined.
>> If the dynamic type contains data members that are not present in the
>> static type, and the static type does not have a virtual constructor,
>> the behavior is undefined.
>> If the dynamic type does not contain data members that are not present
>> in the static type, and the static type does not have a virtual
>> constructor, the behavior is identical to the behavior of deleting an
>> object of the static type.
>> >In the second alternative (delete array) if the dynamic type of the obje
>> ct to be deleted differs from its static type, the behavior is undefined.
>
>I'm afraid this proposal needs work before being considered. For instance,
>'virtual constructors' probably is a thinko which should be 'virtual dtors'.

  Yes, of course. Thank you.

>In addition, I do fear it's not complete. Adding virtual bases, or virtual
>functions in the derived class can reasonably affect the compilers ability
>to treat the base and derived type interchangebly, just as data members do.
>
>Furthermore, in a non-diamond inheritance,
>    D
>   / \
>  B   C
> /     \
>A       A
>, D could contain only data members present in A, yet deleting a D via
>an A* is clearly impossible. What offset should be used ?

>As it stands, I would reject the proposal as being unimplementable.
  How about in the absence of multiple inheritance?


--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Hyman Rosen <hyrosen@mail.com>
Date: Wed, 15 May 2002 16:42:27 GMT
Raw View
Steve Heller wrote:
>   Ok, then restrict it to the case where the derived class doesn't
> define its own new and delete operators or multiple inheritance.

There is no chance - zero - that the committee will adopt such a
limited and dubious feature.

---
[ 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 15 May 2002 16:44:15 GMT
Raw View
In article <b0q0eu80d261qvrr5qkch0snr577m1eofi@4ax.com>, Steve Heller
<steve@steveheller.com> writes
>>At the very least, your proposal would force the placement
>>of the base part of a derived object at zero offset, which
>>is very likely unacceptable.
>
>  Ok, then restrict it to the case where the derived class doesn't
>define its own new and delete operators or multiple inheritance.

As you add restrictions the potential utility decreases and the problem
of teaching people to code safely goes up. The real problem from my
perspective is the use of inheritance to tweak an existing concrete
class. Certainly it would be useful to be able to re-use an existing
class with another name but this needs to be considered as the problem.
IOWs state what problem you are trying to solve and then consider viable
solutions to it. I think that a work item I have from the evolution work
group of WG21 concerning inheriting constructors may throw up more
general solutions to the problem of reusing a (possible tweaked)
concrete class.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: Michiel.Salters@cmg.nl (Michiel Salters)
Date: Wed, 15 May 2002 17:56:06 GMT
Raw View
Steve Heller <steve@steveheller.com> wrote in message news:<hup0euchdpd7v38v3fpafn0bnchb7pctn9@4ax.com>...
> Michiel.Salters@cmg.nl (Michiel Salters) wrote:
>
> >Steve Heller <steve@steveheller.com> wrote in message news:<tdkqduggvj3ghne9pgecnkg3i8mgaju2mq@4ax.com>...
> >> This is a request to the standards committee to change paragraph
> >> 5.3.5.3 of the C++ standard from the following:
> >>
> >> >3 In the first alternative (delete object), if the static type of the op
>  erand is different from its dynamic type, the
> >> >static type shall be a base class of the operand?s dynamic type and th
>  e static type shall have a virtual
> >> >destructor or the behavior is undefined. In the second alternative (dele
>  te array) if the dynamic type of the
> >> >object to be deleted differs from its static type, the behavior is undef
> >> ined.
> >>
> >> to the following:
> >>
> >>
> >> >3 In the first alternative (delete object), if the static type of the op
> >> erand is different from its dynamic type, the
> >> static type shall be a base class of the operand?s dynamic type or the
> >> behavior is undefined.
> >> If the dynamic type contains data members that are not present in the
> >> static type, and the static type does not have a virtual constructor,
> >> the behavior is undefined.
> >> If the dynamic type does not contain data members that are not present
> >> in the static type, and the static type does not have a virtual
> >> constructor, the behavior is identical to the behavior of deleting an
> >> object of the static type.
> >> >In the second alternative (delete array) if the dynamic type of the obje
> >> ct to be deleted differs from its static type, the behavior is undefined.

> >In addition, I do fear it's not complete. Adding virtual bases, or virtual
> >functions in the derived class can reasonably affect the compilers ability
> >to treat the base and derived type interchangebly, just as data members do.
> > [ and MI ]

> >As it stands, I would reject the proposal as being unimplementable.
> How about in the absence of multiple inheritance?

That leaves the unsolved issues of virtual functions and virtual bases.
In addition, the compiler cannot determine at compile time whether
the dynamic type has any of these.

My position on the change with exceptions probably would be negative,
as I don't see a big enough advantage to warrant this change and take
away implementors freedom. But I would need an implementors opinion
on the complete proposal, with exceptions for MI and virtuals, to be
sure.

Regards,
--
Michiel Salters

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Thu, 16 May 2002 08:16:28 GMT
Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:

>In article <b0q0eu80d261qvrr5qkch0snr577m1eofi@4ax.com>, Steve Heller
><steve@steveheller.com> writes
>>>At the very least, your proposal would force the placement
>>>of the base part of a derived object at zero offset, which
>>>is very likely unacceptable.
>>
>>  Ok, then restrict it to the case where the derived class doesn't
>>define its own new and delete operators or multiple inheritance.
>
>As you add restrictions the potential utility decreases and the problem
>of teaching people to code safely goes up. The real problem from my
>perspective is the use of inheritance to tweak an existing concrete
>class. Certainly it would be useful to be able to re-use an existing
>class with another name but this needs to be considered as the problem.
>IOWs state what problem you are trying to solve and then consider viable
>solutions to it. I think that a work item I have from the evolution work
>group of WG21 concerning inheriting constructors may throw up more
>general solutions to the problem of reusing a (possible tweaked)
>concrete class.

  What I would actually like to do is to forward all functions (not
otherwise defined) called on objects of my class to an object of
another class, without having to forward every such function
explicitly, and while maintaining object semantics (i.e, not
overloading ->). The only way I've figured out to do this is by
inheriting publicly from the class to which I want to forward, but I
realize that solution has its own drawbacks. I'm sure others must have
run into this problem, and would also like to see a solution.
  Perhaps the solution should be some sort of declaration that would
say "forward all functions (except those overridden in this class) to
a member object". E.g.,
//////////////////////////
class A
{
  FirstFunction();
  SecondFunction();
};

class B
{
A otherObject;
forward otherObject; // proposed extension
B();
SomeFunction();
FirstFunction();
};

int main()
{
  B b;
  b.SomeFunction(); // invokes b.SomeFunction();
  b.FirstFunction(); // invokes b.FirstFunction();
  b.SecondFunction(); // invokes otherObject.SecondFunction();
}
//////////////////////////

This would not pose the difficulty of allowing a B to be treated as an
A, but would allow B to leverage A's functionality in a safe and
convenient manner.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 16 May 2002 17:13:29 GMT
Raw View
In article <aoe6eu41bukg2ek4rhs6cj60fn7o52n9lp@4ax.com>, Steve Heller
<steve@steveheller.com> writes
>  What I would actually like to do is to forward all functions (not
>otherwise defined) called on objects of my class to an object of
>another class, without having to forward every such function
>explicitly, and while maintaining object semantics (i.e, not
>overloading ->). The only way I've figured out to do this is by
>inheriting publicly from the class to which I want to forward, but I
>realize that solution has its own drawbacks. I'm sure others must have
>run into this problem, and would also like to see a solution.

Some of us (in particular a strong group centred on the UK C++ Panel,
the equivalent of J16) have been working on this problem for some time.
We have various solutions under consideration, such as using directives
applied to a base class, using directives applied to a class member,
strong typedefs (creating real types rather than type aliases) possible
extensions to that to allow strong typedefs + extension, etc. And this
is exactly my point, there is a real problem and it has wider
implications than just somehow fixing destruction semantics for some
limited subset of the cases. We have to consider such things as
assignment operators, constructors, member functions that return the
class type by value, reference or pointer. etc. What about conversions?
If we use public inheritance we get a possibly unwanted derived to base
conversion. What about the problem that class scope using declarations
at public or protected access do not work if the name is used with
private access in the base class (makes it hard when there is an
overloaded set of member functions with a dangerous case locked out with
a private member function declaration) We want a full solution not just
a small fix of part of the problem.

This is why we want problem driven evolution, not just 'wouldn't it be
nice?'

Now just a thought for the day:

class X{
// whatever
};

new typename Y : private class X {};

Y is exactly like X (i.e. imagine rewriting X with Y replacing X
everywhere) but there is no conversion between X and Y

new typename Z : public class X{};

As for Y but Y's convert implicitly to X's

new typename W: private class X{
public:
    void foo();
};

As above but with foo() added or replacing an existing foo.

Just thinking aloud.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Thu, 16 May 2002 19:08:45 GMT
Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:

>In article <aoe6eu41bukg2ek4rhs6cj60fn7o52n9lp@4ax.com>, Steve Heller
><steve@steveheller.com> writes
>>  What I would actually like to do is to forward all functions (not
>>otherwise defined) called on objects of my class to an object of
>>another class, without having to forward every such function
>>explicitly, and while maintaining object semantics (i.e, not
>>overloading ->). The only way I've figured out to do this is by
>>inheriting publicly from the class to which I want to forward, but I
>>realize that solution has its own drawbacks. I'm sure others must have
>>run into this problem, and would also like to see a solution.
>
>Some of us (in particular a strong group centred on the UK C++ Panel,
>the equivalent of J16) have been working on this problem for some time.
>We have various solutions under consideration, such as using directives
>applied to a base class, using directives applied to a class member,
>strong typedefs (creating real types rather than type aliases) possible
>extensions to that to allow strong typedefs + extension, etc. And this
>is exactly my point, there is a real problem and it has wider
>implications than just somehow fixing destruction semantics for some
>limited subset of the cases. We have to consider such things as
>assignment operators, constructors, member functions that return the
>class type by value, reference or pointer. etc. What about conversions?
>If we use public inheritance we get a possibly unwanted derived to base
>conversion. What about the problem that class scope using declarations
>at public or protected access do not work if the name is used with
>private access in the base class (makes it hard when there is an
>overloaded set of member functions with a dangerous case locked out with
>a private member function declaration) We want a full solution not just
>a small fix of part of the problem.
>
>This is why we want problem driven evolution, not just 'wouldn't it be
>nice?'

  I would appreciate your comments on my proposal for "using
inheritance", posted under a new title.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Allan_W@my-dejanews.com (Allan W)
Date: Thu, 16 May 2002 20:16:46 GMT
Raw View
Steve Heller <steve@steveheller.com> wrote
> >>  Ok, then restrict it to the case where the derived class doesn't
> >>define its own new and delete operators or multiple inheritance.

Have you considered just adding a virtual destructor to the base class?
If your concern is run-time efficiency, I urge you to try it and
benchmark it -- my guess is that the difference will be very small in
a test harness, and invisible in a real production setting.

>   What I would actually like to do is to forward all functions (not
> otherwise defined) called on objects of my class to an object of
> another class, without having to forward every such function
> explicitly, and while maintaining object semantics (i.e, not
> overloading ->). The only way I've figured out to do this is by
> inheriting publicly from the class to which I want to forward, but I
> realize that solution has its own drawbacks. I'm sure others must have
> run into this problem, and would also like to see a solution.

Consider this:
    struct A { func1(); func2(); };

    struct B {
    private:
        A a;
    public:
        // Instead of forwarding functions:
        A* operator*() { return &a; }
        A& operator->() { return a; }
    };

B is now a special type of "smart pointer" that automatically
allocates and deallocates A's as needed. Unlike most smart pointers,
the A object is embedded, instead of being on the stack.
    B x;
    x->func1();
    // ... and so on.

---
[ 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 16 May 2002 20:38:33 GMT
Raw View
In article <23b84d65.0205161215.55f61a8c@posting.google.com>, Allan W
<Allan_W@my-dejanews.com> writes
>Consider this:
>    struct A { func1(); func2(); };
>
>    struct B {
>    private:
>        A a;
>    public:
>        // Instead of forwarding functions:
>        A* operator*() { return &a; }
>        A& operator->() { return a; }
>    };
>
>B is now a special type of "smart pointer" that automatically
>allocates and deallocates A's as needed. Unlike most smart pointers,
>the A object is embedded, instead of being on the stack.
>    B x;
>    x->func1();
>    // ... and so on.
being able to overload the dot operator would make this so much more
elegant.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Fri, 17 May 2002 01:30:19 GMT
Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote:

>In article <23b84d65.0205161215.55f61a8c@posting.google.com>, Allan W
><Allan_W@my-dejanews.com> writes
>>Consider this:
>>    struct A { func1(); func2(); };
>>
>>    struct B {
>>    private:
>>        A a;
>>    public:
>>        // Instead of forwarding functions:
>>        A* operator*() { return &a; }
>>        A& operator->() { return a; }
>>    };
>>
>>B is now a special type of "smart pointer" that automatically
>>allocates and deallocates A's as needed. Unlike most smart pointers,
>>the A object is embedded, instead of being on the stack.
>>    B x;
>>    x->func1();
>>    // ... and so on.
>being able to overload the dot operator would make this so much more
>elegant.

  Yes, it certainly would! Is that under consideration? If so, it gets
my vote.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Fri, 17 May 2002 01:30:27 GMT
Raw View
Allan_W@my-dejanews.com (Allan W) wrote:

>Steve Heller <steve@steveheller.com> wrote
>> >>  Ok, then restrict it to the case where the derived class doesn't
>> >>define its own new and delete operators or multiple inheritance.
>
>Have you considered just adding a virtual destructor to the base class?
>If your concern is run-time efficiency, I urge you to try it and
>benchmark it -- my guess is that the difference will be very small in
>a test harness, and invisible in a real production setting.

  Yes, of course, if I could do that it would solve the problem.
Unfortunately, the base class is std::string.

>>   What I would actually like to do is to forward all functions (not
>> otherwise defined) called on objects of my class to an object of
>> another class, without having to forward every such function
>> explicitly, and while maintaining object semantics (i.e, not
>> overloading ->). The only way I've figured out to do this is by
>> inheriting publicly from the class to which I want to forward, but I
>> realize that solution has its own drawbacks. I'm sure others must have
>> run into this problem, and would also like to see a solution.
>
>Consider this:
>    struct A { func1(); func2(); };
>
>    struct B {
>    private:
>        A a;
>    public:
>        // Instead of forwarding functions:
>        A* operator*() { return &a; }
>        A& operator->() { return a; }
>    };
>
>B is now a special type of "smart pointer" that automatically
>allocates and deallocates A's as needed. Unlike most smart pointers,
>the A object is embedded, instead of being on the stack.
>    B x;
>    x->func1();
>    // ... and so on.

  I specifically excluded the solution of overloading -> because it
has ugly syntactic consequences, namely that you can't use operator
notation in any even slightly natural way.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Afraid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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: Adin Hunter Baber <mjolnir_DELETE_@soltec.net>
Date: Fri, 17 May 2002 16:00:45 GMT
Raw View
In article <atm8euc6h2g5md7e1k6j8q1apjnsbgcbh1@4ax.com>,
 Steve Heller <steve@steveheller.com> wrote:

> Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
>
> >In article <23b84d65.0205161215.55f61a8c@posting.google.com>, Allan W
> ><Allan_W@my-dejanews.com> writes
> >>Consider this:
> >>    struct A { func1(); func2(); };
> >>
> >>    struct B {
> >>    private:
> >>        A a;
> >>    public:
> >>        // Instead of forwarding functions:
> >>        A* operator*() { return &a; }
> >>        A& operator->() { return a; }
> >>    };
> >>
> >>B is now a special type of "smart pointer" that automatically
> >>allocates and deallocates A's as needed. Unlike most smart pointers,
> >>the A object is embedded, instead of being on the stack.
> >>    B x;
> >>    x->func1();
> >>    // ... and so on.
> >being able to overload the dot operator would make this so much more
> >elegant.
>
>   Yes, it certainly would! Is that under consideration? If so, it gets
> my vote.
>

I thought that overloading the dot operator was avoided since it could
cause confusion.

Say struct B also has func1().  Which func1() does the following code
call?

B b;
b.func1();

My argument may seem a little contrived.  But think about smart
pointers.  Most smart pointers I have seen do have functions that may be
accessed using the dot operator.  If the dot operator is allowed to be
overloaded, what would the precedence rules be?  Would B::func1() come
before A::func1() or vice versa.  Or would we have to write code like
b.A::func1() and b.B::func1()?

---
[ 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Fri, 17 May 2002 17:02:20 GMT
Raw View
In article <atm8euc6h2g5md7e1k6j8q1apjnsbgcbh1@4ax.com>, Steve Heller
<steve@steveheller.com> writes
>>>B is now a special type of "smart pointer" that automatically
>>>allocates and deallocates A's as needed. Unlike most smart pointers,
>>>the A object is embedded, instead of being on the stack.
>>>    B x;
>>>    x->func1();
>>>    // ... and so on.
>>being able to overload the dot operator would make this so much more
>>elegant.
>
>  Yes, it certainly would! Is that under consideration? If so, it gets
>my vote.

In the early days we thought that allowing overloading of the dot
operator would add complexity without any real benefit. Towards the end
of the process of producing the '98 C++ Standard we realised that it
would be more than a little useful for some aspects of template
programming but it was definitely too late to consider for that release.
It is certainly one of the things we will be looking at very carefully
for next time around. If any implementor would like to provide it as an
extension I am sure that  some of us would appreciate that as a way of
getting practical experience prior to writing it into the standard.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: Michiel.Salters@cmg.nl (Michiel Salters)
Date: Mon, 13 May 2002 17:45:58 GMT
Raw View
Steve Heller <steve@steveheller.com> wrote in message news:<tdkqduggvj3ghne9pgecnkg3i8mgaju2mq@4ax.com>...
> This is a request to the standards committee to change paragraph
> 5.3.5.3 of the C++ standard from the following:
>
> >3 In the first alternative (delete object), if the static type of the op
>  erand is different from its dynamic type, the
> >static type shall be a base class of the operand?s dynamic type and th
>  e static type shall have a virtual
> >destructor or the behavior is undefined. In the second alternative (dele
>  te array) if the dynamic type of the
> >object to be deleted differs from its static type, the behavior is undef
> ined.
>
> to the following:
>
>
> >3 In the first alternative (delete object), if the static type of the op
> erand is different from its dynamic type, the
> static type shall be a base class of the operand?s dynamic type or the
> behavior is undefined.
> If the dynamic type contains data members that are not present in the
> static type, and the static type does not have a virtual constructor,
> the behavior is undefined.
> If the dynamic type does not contain data members that are not present
> in the static type, and the static type does not have a virtual
> constructor, the behavior is identical to the behavior of deleting an
> object of the static type.
> >In the second alternative (delete array) if the dynamic type of the obje
> ct to be deleted differs from its static type, the behavior is undefined.

I'm afraid this proposal needs work before being considered. For instance,
'virtual constructors' probably is a thinko which should be 'virtual dtors'.
In addition, I do fear it's not complete. Adding virtual bases, or virtual
functions in the derived class can reasonably affect the compilers ability
to treat the base and derived type interchangebly, just as data members do.

Furthermore, in a non-diamond inheritance,
    D
   / \
  B   C
 /     \
A       A
, D could contain only data members present in A, yet deleting a D via
an A* is clearly impossible. What offset should be used ?

As it stands, I would reject the proposal as being unimplementable.

Regards,
--
Michiel Salters

---
[ 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: Hyman Rosen <hyrosen@mail.com>
Date: Mon, 13 May 2002 17:46:34 GMT
Raw View
Steve Heller wrote:
> If the dynamic type does not contain data members that are not present
> in the static type, and the static type does not have a virtual
> constructor, the behavior is identical to the behavior of deleting an
> object of the static type.

I assume the above should say "virtual *de*structor".
I believe this proposal has no merit and would seriously
constrain implementations (perhaps as far as making
certain constructs unimplementable).

For one thing, it completely breaks the case of the derived
class having its own new and delete operators.

Here's an example where you have layout problems.

struct vb { virtual void f() { } };
struct base { };
struct derived : vb, base { };
base *bp = new derived;
delete bp;

At the very least, your proposal would force the placement
of the base part of a derived object at zero offset, which
is very likely unacceptable.

---
[ 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: Steve Heller <steve@steveheller.com>
Date: Mon, 13 May 2002 04:23:42 GMT
Raw View
This is a request to the standards committee to change paragraph
5.3.5.3 of the C++ standard from the following:

>3 In the first alternative (delete object), if the static type of the op=
erand is different from its dynamic type, the
>static type shall be a base class of the operand=92s dynamic type and th=
e static type shall have a virtual
>destructor or the behavior is undefined. In the second alternative (dele=
te array) if the dynamic type of the
>object to be deleted differs from its static type, the behavior is undef=
ined.

to the following:


>3 In the first alternative (delete object), if the static type of the op=
erand is different from its dynamic type, the
static type shall be a base class of the operand=92s dynamic type or the
behavior is undefined.
If the dynamic type contains data members that are not present in the
static type, and the static type does not have a virtual constructor,
the behavior is undefined.
If the dynamic type does not contain data members that are not present
in the static type, and the static type does not have a virtual
constructor, the behavior is identical to the behavior of deleting an
object of the static type.
>In the second alternative (delete array) if the dynamic type of the obje=
ct to be deleted differs from its static type, the behavior is undefined.

--
Steve Heller
http://www.steveheller.com
Author of "Learning to Program in C++", "Who's Afraid of C++?", "Who's Af=
raid of More C++?",
"Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are n=
ow available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt

---
[ 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                       ]