Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 2f1014f

Browse files
Merge pull request #2376 from TurkeyMan/destroy_without_initialize
destroy() receives initialize argument
2 parents ed1adbe + 0fe9872 commit 2f1014f

File tree

2 files changed

+70
-30
lines changed

2 files changed

+70
-30
lines changed

changelog/destroy_noinit.dd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added `initialize` template argument to `object.destroy()`.
2+
3+
`object.destroy()` now receives an `initialize` argument to specify whether to re-initialize the object after destruction.

src/object.d

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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
504504
references any other objects. It does $(I not) initiate a GC cycle or free
505505
any 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

527533
private 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

Comments
 (0)