d复制构造器问题

原文
DMD2.101.0起,以下程序成功编译并运行完成:

struct S
{
    this(ref S)
    {
        assert(0);
    }
}

void main()
{
    S[] a = [ S() ];
    auto p = a.ptr;
    // 直到重新分配,追加
    while (a.ptr == p)
        a ~= S(); // 无断定
}

重新分配数组时,程序应该在运行时断定,但是没有,因为没有调用数组元素的复制构造器.
如果更改复制构造器为postblit('this(this)'),则程序期望的在运行时断定.
另见影响了.dup.idup#20879问题.

更清晰:

import std.typecons;
import std.sumtype;
import std.stdio;
import core.memory;

void fun(RefCounted!string foo) {
    SumType!( RefCounted!(string) )[] foo_storage;

    foo_storage ~= SumType!( RefCounted!(string) )(foo);
    foo_storage ~= SumType!( RefCounted!(string) )(foo); // 再分配,但未复制
    foo_storage = null;
}

void clobber()
{
    int[1000] x = 0x123456;
}

void main(){
    RefCounted!( string ) foo = RefCounted!( string )("哈哈");

    fun(foo);
    clobber();
    GC.collect(); // 收集GC中已有项
    writeln(foo);
}

这里:
1.用sumtype创建元素数组.
2.数组不能容纳第二个元素,所以重新分配.然而,没有调用SumType复制构造器.因此'foo'的引用计数为3,但实际有4个引用(单元素数组,双元素数组,及上的原始foo).
3.clobber确保不指向数组.
4.GC.垃集清理3个foo元素,计数减少到0释放.
5.writeln现在正在写垃圾.在我系统上,它只是向屏幕上喷出了随机内存数字.

a~=S()不应调用复制构造器postblit,因为应该在数组原位创建新追加的元素.
问题在,重新分配复制数组.正确调用了postblit,但未正确调用复制构造器.

struct S
{
    this(this)
    {
        writeln("pblit");
    }
}

void main()
{
    S[] a = [ S() ];
    auto p = a.ptr;
    // 直到重新分配,追加
    while (a.ptr == p)
    {
        writeln("loop");
        a ~= S(); // 无断定
    }
}

要么向TypeInfo添加更多特殊成员,要么修改勾挂,以便可向运行时解释如何调用复制构造器.

posted @   zjh6  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示