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