d安全引用计数

原文
要加个@trusted包装器,才能同一起用.
析构器检查dip1000,否则保持@system.

import std.stdio;
import std.typecons;

struct Container
{
    ubyte[] data;
}

struct Blob
{
    ubyte[64] data;
}


void main ()
{
    auto ptr = getPtr();
    writeln(ptr);
    const save = ptr.dup;
    auto other = getPtr();
    assert(save == ptr);
}

ubyte[] getPtr ()
{
    Blob blob;
    RefCounted!Container rc;
    escape(rc.refCountedPayload(), blob);
    assert(rc.refCountedPayload().data !is null);
    return rc.refCountedPayload().data;
}

void escape (ref Container rc, ref Blob local)
{
    rc.data = local.data;
}

编译,运行,崩溃.
不过,更像是编译器错误而不是RefCounted错误
是的,可滥用:

@safe unittest //编译
{
    void escape (ref ubyte[] arr, ref ubyte[64] local)
    {
        arr = local;
    }

    @safe ubyte[] getPtr ()
    {
        ubyte[64] blob;
        ubyte[] arr;
        escape(arr, blob);
        return arr; // 就像c时代.
    }
}

提交错误
已修复

opAssign按值,而非按引用.

准备实现侵改:

@safe unittest
{
    @safe void assignCrap(RefCounted!(int*) countedRef)
    {
        int local;
        auto anotherRef = countedRef;
//anotherRef生命期更短.
        anotherRef.refCountedPayload() = &local; // ...这样,这会编译
    }
}

编译器未实现,可能refCountedPayload中的return属性,使得,生命期(负载)<生命期(anotherRef).
可能,构+成员函数侵改.

这是有问题的:

@safe unittest
{
    auto rc = RefCounted!int(123);
    (ref int n) {
        destroy(rc);
        int oops = n; // 释放后使用.
    }(rc.refCountedPayload);
}

为确保不在@safe中发生,refCountedPayload析构器必须是@system.

简单变体:

@safe unittest
{
    auto rc = RefCounted!int(123);
    int* ptr = &rc.refCountedPayload();
    destroy(rc);
    int oops = *ptr;
}

问题是,允许域前析构rc.只能在生命期性调用析构器算@safe,其余不应@safe.在@live中可安全,其他则不是.
-dip1000也会:

@safe void abuse(Container)()
{ auto cont = Container([1,2,3]);
  scope ptr = &cont.front;
  destroy(cont);
  int oops = *ptr;
}

可基于回调api

auto ref apply(alias callback, T)(auto ref RefCounted!T this_)
{
    //确保在`callback`返回前保持引用
    auto hold = this_;
    //显式`域`防止`callback`逃逸引用
    scope ptr = () @trusted { return &this_.refCountedPayload(); }();
    return callback(*ptr);
}

// Usage
@safe unittest
{
    auto rc = RefCounted!int(123);
    rc.apply!((ref n) {
        destroy(rc);
        int ok = n; // 仍活着.
    });
}

缺点是:1,语法不好.2,额外引用计数.
在真正所有权/借用前(@live不算),提供2个版本:
@safe为愿意接受运行时成本用户提供基于回调API,及@system提供直接访问的API,并让用户有责任不创建悬空引用.
即,使refCountedPayload为@system,加个@safeapply.
有人destroy了两次,怎么办?

析构器应重置_refCountedRefCountedStore.init,确保即使使用destroy!false,它也是幂等的.

refCountedPayload@safe中工作,析构器为私有,并定义noEarlyDestroy属性,
对注解为noEarlyDestroydestroy应为@system.
有人提出.
由于应阻止安全访问私字段而绕过.

__traits(getMember)破坏@safe的所有东西,可以假装它不存在.
__traits(getMember)很难修复,也是@system变量动机,用来阻塞@safe访问不依赖private的代码.
我们不应让@安全破坏.同时,不应加依赖内存安全特征.

DIP1035可解决大部分__traits(getmember),或许@safe访问会成为特性而不是漏洞.
不一致,在Nullable上与RefCounted上用apply,前者不做啥,后者初化并触发断定,不一致.

重命名更好.因为两个版本处理回调返回值方式不同.

rc.borrow!((scope ref payload) { /* ... */ });
rc.withPayload!((scope ref payload) { /* ... */ });

borrow不错.
-preivew=dip1000编译.
发现问题:
虽然确实可使dirEntries模板来解决链接问题,即使模板化它和或添加析构器,但DirIterator有些生成析构器不会消失.尝试链接的符号在后者中变化了,仅此而已.目前在找原因.

struct _DirIteratorTempl()
{
  //实现
}

alias DirIterator = _DirIteratorTempl!();

auto dirEntries()(string path, SpanMode mode, bool followSymlink = true)
{
  //工作,无链接错误.
  return _DirIteratorTempl!()(path, mode, followSymlink);
}

auto dirEntries()(string path, SpanMode mode, bool followSymlink = true)
{
    //报错,好像_DirIteratorTempl不是模板!
  return DirIterator(path, mode, followSymlink);

}

未记录DirIterator,可修改,算运气了.

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