@@ -499,29 +499,35 @@ unittest
499
499
}
500
500
501
501
/**
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
503
503
_destroy an object, calling its destructor or finalizer so it no longer
504
504
references any other objects. It does $(I not) initiate a GC cycle or free
505
505
any GC memory.
506
+ If `initialize` is supplied `false`, the object is considered invalid after
507
+ destruction, and should not be referenced.
506
508
*/
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 ))
508
510
{
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)
517
514
{
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
+ }
520
526
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
+ }
525
531
}
526
532
527
533
private void _destructRecurse (S)(ref S s)
@@ -539,6 +545,8 @@ nothrow @safe @nogc unittest
539
545
struct A { string s = " A" ; }
540
546
A a;
541
547
a.s = " asd" ;
548
+ destroy ! false (a);
549
+ assert (a.s == " asd" );
542
550
destroy (a);
543
551
assert (a.s == " A" );
544
552
}
@@ -565,32 +573,41 @@ nothrow @safe @nogc unittest
565
573
B a;
566
574
a.s = " asd" ;
567
575
a.c.s = " jkl" ;
568
- destroy (a);
576
+ destroy ! false (a);
569
577
assert (destroyed == 2 );
578
+ assert (a.s == " asd" );
579
+ assert (a.c.s == " jkl" );
580
+ destroy (a);
581
+ assert (destroyed == 4 );
570
582
assert (a.s == " B" );
571
583
assert (a.c.s == " C" );
572
584
}
573
585
}
574
586
575
587
576
588
// / ditto
577
- void destroy (T)(T obj) if (is (T == class ))
589
+ void destroy (bool initialize = true , T)(T obj) if (is (T == class ))
578
590
{
579
591
static if (__traits(getLinkage, T) == " C++" )
580
592
{
581
593
obj.__xdtor();
582
594
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
+ }
585
600
}
586
601
else
587
602
rt_finalize(cast (void * )obj);
588
603
}
589
604
590
605
// / ditto
591
- void destroy (T)(T obj) if (is (T == interface ))
606
+ void destroy (bool initialize = true , T)(T obj) if (is (T == interface ))
592
607
{
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);
594
611
}
595
612
596
613
// / Reference type demonstration
@@ -653,10 +670,15 @@ nothrow @safe @nogc unittest
653
670
cpp.s = " T" ;
654
671
cpp.a.x = 30 ;
655
672
assert (cpp.s == " T" ); // `cpp.s` is `"T"`
656
- destroy (cpp);
673
+ destroy ! false (cpp); // destroy without initialization
657
674
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
659
676
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
660
682
assert (cpp.a.x == 10 ); // `cpp.a.x` is back to its inital state, `10`
661
683
}
662
684
@@ -667,6 +689,8 @@ nothrow @safe @nogc unittest
667
689
assert (i == 0 ); // `i`'s initial state is `0`
668
690
i = 1 ;
669
691
assert (i == 1 ); // `i` changed to `1`
692
+ destroy ! false (i);
693
+ assert (i == 1 ); // `i` was not initialized
670
694
destroy (i);
671
695
assert (i == 0 ); // `i` is back to its initial state `0`
672
696
}
@@ -766,6 +790,8 @@ nothrow @safe @nogc unittest
766
790
struct A { string s = " A" ; }
767
791
A a;
768
792
a.s = " asd" ;
793
+ destroy ! false (a);
794
+ assert (a.s == " asd" );
769
795
destroy (a);
770
796
assert (a.s == " A" );
771
797
}
@@ -792,25 +818,31 @@ nothrow @safe @nogc unittest
792
818
B a;
793
819
a.s = " asd" ;
794
820
a.c.s = " jkl" ;
795
- destroy (a);
821
+ destroy ! false (a);
796
822
assert (destroyed == 2 );
823
+ assert (a.s == " asd" );
824
+ assert (a.c.s == " jkl" );
825
+ destroy (a);
826
+ assert (destroyed == 4 );
797
827
assert (a.s == " B" );
798
828
assert (a.c.s == " C" );
799
829
}
800
830
}
801
831
802
832
// / 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 ))
804
834
{
805
835
foreach_reverse (ref e; obj[])
806
- destroy (e);
836
+ destroy ! initialize (e);
807
837
}
808
838
809
839
unittest
810
840
{
811
841
int [2 ] a;
812
842
a[0 ] = 1 ;
813
843
a[1 ] = 2 ;
844
+ destroy ! false (a);
845
+ assert (a == [ 1 , 2 ]);
814
846
destroy (a);
815
847
assert (a == [ 0 , 0 ]);
816
848
}
@@ -823,7 +855,7 @@ nothrow @safe @nogc unittest
823
855
}
824
856
825
857
vec2f v;
826
- destroy ! vec2f(v);
858
+ destroy ! ( true , vec2f) (v);
827
859
}
828
860
829
861
unittest
@@ -864,10 +896,11 @@ nothrow @safe @nogc unittest
864
896
}
865
897
866
898
// / ditto
867
- void destroy (T)(ref T obj)
899
+ void destroy (bool initialize = true , T)(ref T obj)
868
900
if (! is (T == struct ) && ! is (T == interface ) && ! is (T == class ) && ! _isStaticArray! T)
869
901
{
870
- obj = T.init;
902
+ static if (initialize)
903
+ obj = T.init;
871
904
}
872
905
873
906
template _isStaticArray (T : U[N], U, size_t N)
@@ -884,11 +917,15 @@ nothrow @safe @nogc unittest
884
917
{
885
918
{
886
919
int a = 42 ;
920
+ destroy ! false (a);
921
+ assert (a == 42 );
887
922
destroy (a);
888
923
assert (a == 0 );
889
924
}
890
925
{
891
926
float a = 42 ;
927
+ destroy ! false (a);
928
+ assert (a == 42 );
892
929
destroy (a);
893
930
assert (isnan(a));
894
931
}
0 commit comments