[Issue 15708] std.range.choose assumes hasElaborateCopyConstructor means "has __postblit"

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Sun Jun 11 03:57:41 PDT 2017


https://issues.dlang.org/show_bug.cgi?id=15708

Johannes Loher <johannes.loher at fg4f.de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |johannes.loher at fg4f.de

--- Comment #1 from Johannes Loher <johannes.loher at fg4f.de> ---
After playing around a bit, I found out that the postblit defined in choose
does not result in correct behaviour anyways. Consider the following example:

import std.stdio : writeln;
import std.range : choose, repeat;

struct StructWithPostblit
{
    this(this)
    {
        writeln("StructWithPostblit.__postblit() called");
    }
}

struct MyRange
{
    enum empty = false;
    enum front = 1;
    void popFront() {}

    StructWithPostblit structWithPostblit;

    this(this)
    {
        writeln("MyRange.__postblit() called");
    }
}

void main()
{
    MyRange r1;
    auto r2 = choose(true, r1, repeat(1));
    writeln();

    auto r3 = r2;
}


The programs output:

StructWithPostblit.__postblit() called
MyRange.__postblit() called
StructWithPostblit.__postblit() called
MyRange.__postblit() called
StructWithPostblit.__postblit() called
MyRange.__postblit() called

MyRange.__postblit() called


As you can see, when copying a std.range.choose.Result, the postblit of the
chosen underlying range (if any) gets called, but postblits of members of that
underlying range don't (they should!).

I see 2 possible solutions to this (and the original issue):

1. Similarly, too how hasElaborateCopyconstructor works, recursively check for
all members of of the underlying range, if they define __postblit(). If they
do, call it.

2. Simply make std.range.choose.Result have 2 members R1 and R2 instead of only
a buffer large enough to fit the larger one of those two.


I am actually in favor of the second apporach. I suppose the reason for using a
buffer was to save a little memory. But in my opinion, this is only a really
smallbenefit and makes the constructor, the postblit (as we can see it's buggy
right now..) and the destructor much more complicated for only very little
benefit (saving the memory, that the smaller one of the 2 ranges would occupy).
Using the second approach would probably also solve
https://issues.dlang.org/show_bug.cgi?id=14660, as that one is also caused by
the use of the void[] buffer.


Any opinions on that?

--


More information about the Digitalmars-d-bugs mailing list