Arrays of noncopyables/Invalid memory operation
Matt Elkins via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Feb 17 14:20:00 PST 2016
So in a different thread someone mentioned that when arrays are
grown an implicit copy could be called on all the elements, as
they might need to be copied over to a new, larger block of
memory. This makes sense, and is expected. However, it got me
concerned: what if the post-blit was disabled because it is
illegal to copy the object? I am using a lot of objects exactly
like this, and wanted to make sure my program wasn't working by
coincidence since my dynamic arrays are still small for now. So I
tested:
[code]
import std.stdio;
@safe:
bool scopeEnded;
struct Foo
{
@disable this(this);
this(int val) {writeln("Constructing: ", val, " (", &this,
")"); value = val;}
~this() {writeln("Destroying: ", value, " (", &this, ")");
assert(value == int.init || scopeEnded);}
int value;
}
unittest
{
Foo[] foos;
for (auto i = 0; i < 10000; ++i)
{
++foos.length;
foos[$ - 1] = Foo(i);
}
writeln("Scope about to end");
scopeEnded = true;
}
[/code]
[output]
Constructing: 0 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 1 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 2 (18FDA8)
Destroying: 0 (18FD6C)
....<snipped>....
Constructing: 410 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 411 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 412 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 413 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 414 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 415 (18FDA8)
Destroying: 0 (18FD6C)
core.exception.InvalidMemoryOperationError at src\core\exception.d(679): Invalid memory operation
Constructing: 416 (18FDA8)
----------------
Destroying: 0 (18FD6C)
Constructing: 417 (18FDA8)
core.exception.InvalidMemoryOperationError at src\core\exception.d(679): Invalid memory operation
Destroying: 0 (18FD6C)
Constructing: 418 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 419 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 420 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 421 (18FDA8)
----------------
Destroying: 0 (18FD6C)
Constructing: 422 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 423 (18FDA8)
....<snipped>....
Constructing: 506 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 507 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 508 (18FDA8)
Destroying: 0 (18FD6C)
Constructing: 509 (18FDA8)
Destroying: 0 (18FD6C)
Destroying: 29 (5201F4)
Program exited with code 1
[/output]
Note that the invalid memory operation lines change relative
order in this output, I think maybe it is stderr instead of
stdout.
So now I'm wondering:
* Is the fact that this compiles a bug? If copying can happen
under the hood, shouldn't the @disable this(this) prevent Foo
being used this way? Or should copying be happening at all (the
compiler could instead choose to "move" the Foo by blitting it
and NOT running the destructor...though I don't know whether that
is a safe choice in the general case)?
* What is the invalid memory operation? It doesn't occur if I
remove the assert or make the assert never fail, so I'm guessing
it has to do with failing an assert in the destructor? This
points bothers me less than the previous one because I don't
expect an assert-failing program to behave nicely anyway.
More information about the Digitalmars-d-learn
mailing list