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@src\core\exception.d(679): Invalid 
memory operation
Constructing: 416 (18FDA8)
----------------
Destroying: 0 (18FD6C)

Constructing: 417 (18FDA8)
core.exception.InvalidMemoryOperationError@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.

Reply via email to