Destructors, const structs, and opEquals

kenji hara k.hara.pg at gmail.com
Sat Dec 4 07:24:49 PST 2010


Andrei, your explanation is almost the same as was my understanding. Thank you.

My shallow thought:
  const T makes automatically reference. It is convenient.
Right thinking:
  D has no semantics dividing copying/referencing, against has
dividing rvalue/lvalue.
  D should support this like T(copying)/T&(referencing).

Thanks.

Kenji

2010/12/4 Andrei Alexandrescu <SeeWebsiteForEmail at erdani.org>:
> On 12/4/10 12:42 AM, Don wrote:
>>
>> Officially, opEquals has to have the signature:
>>
>> struct Foo {
>> bool opEquals(const ref Foo x) const {...}
>> }
>
> This is a compiler bug. For structs there should be no official
> implementation of opEquals, opCmp etc. All the compiler needs to worry about
> is to syntactically translate a == b to a.opEquals(b) and then let the usual
> language rules resolve the call.
>
>> But this disallows comparisons with rvalues.
>> eg,
>>
>> Foo bar() { Foo x = 1; return x; }
>> Foo y=1;
>> assert( y == bar() ); // doesn't compile
>>
>> You can get around this by declaring a non-ref opEquals.
>> But this fails if Foo has a destructor.
>>
>> If a struct has a destructor, it cannot be const(this is bug 3606)
>> ---
>> struct S {
>> ~this() {}
>> }
>>
>> void main() {
>> const S z;
>> }
>> ---
>> bug.d(6): Error: destructor bug.S.~this () is not callable using
>> argument types ()
>> -------
>> Likewise, it can't be a const parameter (this is bug 4338).
>> void foo(const S a) {}
>> It works to have it as a const ref parameter.
>>
>> Everything will work if you declare a const ~this(), but that seems a
>> little nonsensical. And you cannot have both const and non-const ~this().
>>
>> I'm a bit uncertain as to how this is all supposed to work.
>> (1) Should temporaries be allowed to be passed as 'const ref'?
>> (2) If a struct has a destructor, should it be passable as a const
>> parameter? And if so, should the destructor be called?
>
> This is a delicate matter that clearly needs a solution. Pass of temporaries
> by const ref was a huge mistake of C++ that it has paid dearly for and
> required the introduction of a large complication, the rvalue references
> feature, to just undo the effects of that mistake. So I don't think we
> should allow that.
>
> Regarding destructors, for every constructed object ever there must be a
> corresponding destructor call. One issue that has been a matter of debate in
> C++ has been the fact that any object becomes "deconstified" during
> destruction. The oddest consequence of that rule is that in C++ you can
> delete a pointer to a const object:
>
> // C++ code
> class A { ... };
> void fun(const A* p) { delete p; /* fine */ }
>
> There has been a lot of opposition. const is supposed to limit what you can
> do with that object, and the fact that you can't invoke certain methods or
> change members, but you can nuke the entire object, is quite nonintuitive
> (and leads to a lot of funny real-life comparisons such as "You can go out
> with my daughter, but no touching. Of course, you can shoot her if you so
> wish.")
>
> In D, the rule must be inferred from D's immutability rules, which pretty
> much dictate that the destructor must be overloaded for non-const and const
> (and possibly invariant if the struct needs that).
>
>
> Andrei
>


More information about the Digitalmars-d mailing list