When should value parameters be destroyed?
Jim Dehnert
dehnert at baalbek.engr.sgi.com
Fri Sep 29 19:15:24 UTC 2000
> From: Martin von Loewis <loewis at informatik.hu-berlin.de>
>
> > Those of us present could not remember why destructors were included
> > here, and decided it was probably a mistake, and intend to remove it
> > (for both value parameters and results), if a request for rationale
> > yields nothing. Consider this message such a request.
>
> Maybe that was an overlap in messages, but it appears that Daveed
> already pointed to the right place: 5.2.2/4 explains the life time of
> parameters. Mark's reference of 12.2/3 is not relevant - parameters
> are not temporaries; instead, temporaries may be used to initialize
> the parameters.
Yes, it was an overlap.
> The critical point is that access checks must be made in the caller,
> so
>
> struct A{
> private:
> ~A();
> friend void bar();
> };
>
> void foo(A a){
> }
>
> void bar(){
> A a;
> foo(a);
> }
>
> Since g++ invokes the destructor in the callee, it incorrectly rejects
> this code:
>
> a.cc: In function `void foo(A)':
> a.cc:3: `A::~A()' is private
> a.cc:7: within this context
>
> Of course, the compiler could *still* invoke the destructor in the
> callee under the as-if-rule, provided the access check occurs in the
> caller.
But the access check is compile-time, right? There's nothing to
prevent a compiler from doing it at the call, but still calling the
parameter destructor in the callee (without checking), right?
Nevertheless:
> That gets tricky since there are other conditions as well, e.g. that
> destruction must occur outside a function-try-block of the callee - so
> I'm in favour of having the caller destroy the object.
This seems important to me. One could still, I suppose, call the
destructor in the callee, but outside its try-block if any. But this
gets to be a complicated implementation, and I don't think we want to
require this treatment. The ABI must choose one approach, so I guess
I'm now convinced it should be to invoke the destructor in the caller.
Anyone else have issues to raise before I make that explicit?
> I have also concerns about the callee invoking the copy constructor,
> if any. 8.5/12 states that parameter passing is copy-initialization,
> and 12.8.15 gives permission to elide the call to the copy
> constructor. Is this ABI giving the same permission to
> implementations?
Yes, it does. The second bullet in 3.1.1 leaves parameter construction
to the caller, which can elide it when allowed to do so, e.g. in your
example below. (The fourth bullet is a typo -- "copy constructor"
should have read "destructor," and will soon.)
> Consider
>
> struct A{
> A(int);
> A(const A&);
> ~A();
> };
>
> void foo(A a){}
>
> int getint();
>
> void bar(){
> foo(getint());
> }
>
> In C++, two sequences of calls are possible:
>
> 1. getint, A(int), A(const A&), foo, ~A, ~A.
> 2. geting, A(int), foo, ~A.
>
> It appears that the ABI mandates sequence A, since the copy ctor will
> be called inside foo. I think this is not desirable; furthermore, the
> same issue with access check and function-try-blocks arises.
My mistake (editorial) -- see above. The ABI doesn't mandate (1).
> So I propose to take 5.2.2 literal, and require parameter ctors and
> dtors to be called *in* the caller.
Agreed. If anyone feels differently about this, speak up now...
Jim
- Jim Dehnert dehnert at sgi.com
(650)933-4272
More information about the cxx-abi-dev
mailing list