@@ -499,29 +499,35 @@ unittest
499499}
500500
501501/**
502- Destroys the given object and sets it back to its initial state. It's used to
502+ Destroys the given object and optionally resets to initial state. It's used to
503503_destroy an object, calling its destructor or finalizer so it no longer
504504references any other objects. It does $(I not) initiate a GC cycle or free
505505any GC memory.
506+ If `initialize` is supplied `false`, the object is considered invalid after
507+ destruction, and should not be referenced.
506508*/
507- void destroy (T)(ref T obj) if (is (T == struct ))
509+ void destroy (bool initialize = true , T)(ref T obj) if (is (T == struct ))
508510{
509- // We need to re-initialize `obj`. Previously, an immutable static
510- // and memcpy were used to hold an initializer. With improved unions, this is no longer
511- // needed.
512- union UntypedInit
513- {
514- T dummy;
515- }
516- static struct UntypedStorage
511+ _destructRecurse(obj);
512+
513+ static if (initialize)
517514 {
518- align (T.alignof) void [T.sizeof] dummy;
519- }
515+ // We need to re-initialize `obj`. Previously, an immutable static
516+ // and memcpy were used to hold an initializer. With improved unions, this is no longer
517+ // needed.
518+ union UntypedInit
519+ {
520+ T dummy;
521+ }
522+ static struct UntypedStorage
523+ {
524+ align (T.alignof) void [T.sizeof] dummy;
525+ }
520526
521- _destructRecurse(obj);
522- () @trusted {
523- * cast (UntypedStorage * ) &obj = cast (UntypedStorage) UntypedInit.init ;
524- } ();
527+ () @trusted {
528+ * cast (UntypedStorage * ) &obj = cast (UntypedStorage) UntypedInit.init;
529+ } () ;
530+ }
525531}
526532
527533private void _destructRecurse (S)(ref S s)
@@ -539,6 +545,8 @@ nothrow @safe @nogc unittest
539545 struct A { string s = " A" ; }
540546 A a;
541547 a.s = " asd" ;
548+ destroy ! false (a);
549+ assert (a.s == " asd" );
542550 destroy (a);
543551 assert (a.s == " A" );
544552 }
@@ -565,32 +573,41 @@ nothrow @safe @nogc unittest
565573 B a;
566574 a.s = " asd" ;
567575 a.c.s = " jkl" ;
568- destroy (a);
576+ destroy ! false (a);
569577 assert (destroyed == 2 );
578+ assert (a.s == " asd" );
579+ assert (a.c.s == " jkl" );
580+ destroy (a);
581+ assert (destroyed == 4 );
570582 assert (a.s == " B" );
571583 assert (a.c.s == " C" );
572584 }
573585}
574586
575587
576588 // / ditto
577- void destroy (T)(T obj) if (is (T == class ))
589+ void destroy (bool initialize = true , T)(T obj) if (is (T == class ))
578590 {
579591 static if (__traits(getLinkage, T) == " C++" )
580592 {
581593 obj.__xdtor();
582594
583- enum classSize = __traits(classInstanceSize, T);
584- (cast (void * )obj)[0 .. classSize] = typeid (T).initializer[];
595+ static if (initialize)
596+ {
597+ enum classSize = __traits(classInstanceSize, T);
598+ (cast (void * )obj)[0 .. classSize] = typeid (T).initializer[];
599+ }
585600 }
586601 else
587602 rt_finalize(cast (void * )obj);
588603 }
589604
590605 // / ditto
591- void destroy (T)(T obj) if (is (T == interface ))
606+ void destroy (bool initialize = true , T)(T obj) if (is (T == interface ))
592607 {
593- destroy (cast (Object )obj);
608+ static assert (__traits(getLinkage, T) == " D" , " Invalid call to destroy() on extern(" ~ __traits(getLinkage, T) ~ " ) interface" );
609+
610+ destroy ! initialize(cast (Object )obj);
594611 }
595612
596613 // / Reference type demonstration
@@ -653,10 +670,15 @@ nothrow @safe @nogc unittest
653670 cpp.s = " T" ;
654671 cpp.a.x = 30 ;
655672 assert (cpp.s == " T" ); // `cpp.s` is `"T"`
656- destroy (cpp);
673+ destroy ! false (cpp); // destroy without initialization
657674 assert (cpp.dtorCount == 1 ); // `cpp`'s destructor was called
658- assert (cpp.s == " S " ); // `cpp.s` is back to its inital state, `"S"`
675+ assert (cpp.s == " T " ); // `cpp.s` is not initialized
659676 assert (cpp.a.dtorCount == 1 ); // `cpp.a`'s destructor was called
677+ assert (cpp.a.x == 30 ); // `cpp.a.x` is not initialized
678+ destroy (cpp);
679+ assert (cpp.dtorCount == 2 ); // `cpp`'s destructor was called again
680+ assert (cpp.s == " S" ); // `cpp.s` is back to its inital state, `"S"`
681+ assert (cpp.a.dtorCount == 2 ); // `cpp.a`'s destructor was called again
660682 assert (cpp.a.x == 10 ); // `cpp.a.x` is back to its inital state, `10`
661683 }
662684
@@ -667,6 +689,8 @@ nothrow @safe @nogc unittest
667689 assert (i == 0 ); // `i`'s initial state is `0`
668690 i = 1 ;
669691 assert (i == 1 ); // `i` changed to `1`
692+ destroy ! false (i);
693+ assert (i == 1 ); // `i` was not initialized
670694 destroy (i);
671695 assert (i == 0 ); // `i` is back to its initial state `0`
672696 }
@@ -766,6 +790,8 @@ nothrow @safe @nogc unittest
766790 struct A { string s = " A" ; }
767791 A a;
768792 a.s = " asd" ;
793+ destroy ! false (a);
794+ assert (a.s == " asd" );
769795 destroy (a);
770796 assert (a.s == " A" );
771797 }
@@ -792,25 +818,31 @@ nothrow @safe @nogc unittest
792818 B a;
793819 a.s = " asd" ;
794820 a.c.s = " jkl" ;
795- destroy (a);
821+ destroy ! false (a);
796822 assert (destroyed == 2 );
823+ assert (a.s == " asd" );
824+ assert (a.c.s == " jkl" );
825+ destroy (a);
826+ assert (destroyed == 4 );
797827 assert (a.s == " B" );
798828 assert (a.c.s == " C" );
799829 }
800830 }
801831
802832 // / ditto
803- void destroy (T : U[n], U, size_t n)(ref T obj) if (! is (T == struct ))
833+ void destroy (bool initialize = true , T : U[n], U, size_t n)(ref T obj) if (! is (T == struct ))
804834 {
805835 foreach_reverse (ref e; obj[])
806- destroy (e);
836+ destroy ! initialize (e);
807837 }
808838
809839 unittest
810840 {
811841 int [2 ] a;
812842 a[0 ] = 1 ;
813843 a[1 ] = 2 ;
844+ destroy ! false (a);
845+ assert (a == [ 1 , 2 ]);
814846 destroy (a);
815847 assert (a == [ 0 , 0 ]);
816848 }
@@ -823,7 +855,7 @@ nothrow @safe @nogc unittest
823855 }
824856
825857 vec2f v;
826- destroy ! vec2f(v);
858+ destroy ! ( true , vec2f) (v);
827859 }
828860
829861 unittest
@@ -864,10 +896,11 @@ nothrow @safe @nogc unittest
864896 }
865897
866898 // / ditto
867- void destroy (T)(ref T obj)
899+ void destroy (bool initialize = true , T)(ref T obj)
868900 if (! is (T == struct ) && ! is (T == interface ) && ! is (T == class ) && ! _isStaticArray! T)
869901 {
870- obj = T.init;
902+ static if (initialize)
903+ obj = T.init;
871904 }
872905
873906 template _isStaticArray (T : U[N], U, size_t N)
@@ -884,11 +917,15 @@ nothrow @safe @nogc unittest
884917 {
885918 {
886919 int a = 42 ;
920+ destroy ! false (a);
921+ assert (a == 42 );
887922 destroy (a);
888923 assert (a == 0 );
889924 }
890925 {
891926 float a = 42 ;
927+ destroy ! false (a);
928+ assert (a == 42 );
892929 destroy (a);
893930 assert (isnan(a));
894931 }
0 commit comments