Bug 15009 – Object.destroy calls unnecessary postblits for destruction of static arrays object
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-09-03T18:01:00Z
Last change time
2015-10-04T18:19:19Z
Keywords
pull
Assigned to
nobody
Creator
nicolas.jinchereau
Comments
Comment #0 by nicolas.jinchereau — 2015-09-03T18:01:23Z
struct S {
int x;
this(int x) { writeln("ctor"); }
this(this) { writeln("ctor(postblit)"); }
~this() { writeln("dtor"); }
}
void main(string[] args) {
S[2]* arr = cast(S[2]*)calloc(1, S.sizeof);
emplace(arr, S(1));
destroy(*arr);
free(arr);
}
output has 5 ctors, and 3 dtors:
ctor
ctor(postblit)
ctor(postblit)
dtor
ctor(postblit)
dtor
ctor(postblit)
dtor
fix is to modify this overload of Object.destroy:
void destroy(T : U[n], U, size_t n)(ref T obj)
if (!is(T == struct))
{
typeid(T).destroy(&obj); // +++
obj[] = U.init;
}
output now has 5 ctors, and 5 dtors, as expected:
ctor
ctor(postblit)
ctor(postblit)
dtor
dtor
dtor
ctor(postblit)
dtor
ctor(postblit)
dtor
Comment #1 by k.hara.pg — 2015-09-03T21:23:47Z
The bug in Object.destroy overload for the static array is, that is using block assignment.
void destroy(T : U[n], U, size_t n)(ref T obj)
if (!is(T == struct))
{
obj[] = U.init;
}
obj[] = U.init; _copies_ the rhs for each elements of lhs, and destroys the original elements of lhs. Instead of that, it should just destroy the elements.
And, the order of destroying should occur from the last to the first.
Then' the fixed destroy function should be:
void destroy(T : U[n], U, size_t n)(ref T obj)
if (!is(T == struct))
{
foreach_reverse (ref e; obj[])
e = U.init;
}
Comment #2 by k.hara.pg — 2015-09-03T21:41:33Z
Note that, destroy actually calls destructors.
import std.stdio, std.conv, core.stdc.stdlib;
struct S {
int x;
this(int x) { writeln("ctor"); }
this(this) { writeln("ctor(postblit)"); }
~this() { writeln("dtor"); }
}
void main(string[] args) {
S[2]* arr = cast(S[2]*)calloc(1, S.sizeof);
printf("-- calloc done\n");
emplace(arr, S(1));
printf("-- emplace done\n");
destroy(*arr);
printf("-- destroy done\n");
//typeid(*arr).destroy(&arr);
free(arr);
printf("-- free done\n");
}
output is:
$ dmd -run test
-- calloc done
ctor
ctor(postblit)
ctor(postblit)
dtor
-- emplace done
ctor(postblit)
dtor
ctor(postblit)
dtor
-- destroy done
-- free done
My point is , the two postblit calls invoked by destroy() is unnecessary.