来自翻译者。我通常不会翻译此类文章,因为我看不到任何有趣的内容。这里有两个小但最重要的创新-支持C ++库的直接链接以及从Rust所有权和借用的“借来的”所有权和借用系统(第二个是DFA吞咽,第一个是几天前在GCC10中出现的,Nim也这样考虑),并带有描述。实际上,我没有翻译任何繁琐的列表,并且链接指向原始列表。清单2.0.91.1(eng)的先前版本下载了2.092.0,其中进行了15项重要更改,并修正了44个错误。非常感谢47位贡献者使这次发布成为可能。编译器变更
- -revert = import和-transition = checkimports命令行开关已删除
- 添加了对C ++ GNU ABI名称编码(篡改)的支持
- 非外部(D)的模块的构造函数和析构函数标记为过时
- DIP25违规默认标记为过时
- 指针的原型所有权和借用系统
- 新增-preview =在选项打开的存储类在进入范围常量
- 现在检查Printf和scanf参数是否符合格式说明符
- 现在支持环境变量SOURCE_DATE_EPOCH。
运行时更改
- TypeInfo_Class/TypeInfo_Interface.isBaseOf C#/Java isAssignableFrom
- core.memory.pageSize minimumPageSize
- Date.isoWeekYear Date.fromISOWeek std.datetime.date
- std.xml
- std.digest.digest
Dub
- Dub lint --report-file
修复和改进的完整列表(英语)Prim.per.U,请您谅解,因为无法设置指向披露内容的页内链接的正确内容,就像原始内容一样,对不起=(编译器变更
- 命令行开关-revert = import和-transition = checkimports已删除。
这些键没有任何作用,并且一段时间以来,它们被标记为过时。编译器将不再识别它们。 - () C++ GNU ABI
GNU ABI C++11 GCC 5.1. D C++, DMD UDA ( ) gnuAbiTag, core.attribute object ( ). ABI , , ++ . , std::string C++11 (DMD -extern-std={c++11,c++14,c++17}).
:
extern(C++):
@gnuAbiTag("tagOnStruct")
struct MyStruct {}
@gnuAbiTag("Multiple", "Tags", "On", "Function")
MyStruct func();
gnuAbiTag. ( ). UDA -extern-std=c++11. (-extern-std=c++98) UDA . UDA extern(C++) . - , extern(D) .
( ) , extern(D), . , , / , , 479, 479, .
, , . - DIP25 .
DIP25 2.067.0, , -preview=dip25. , , DIP1000.
, , -preview=dip25, -preview=dip25. ( ).
DIP25 , @ safe . , ref , return , .
struct Foo
{
int x;
ref int method() { return this.x; }
}
ref int identity( ref int v) { return v; }
return . DIP25 . - -preview=in in scope const.
const scope, in . , in (. inout ) .
-preview=in, :
void fun(in int x);
void fun(const int x);
-preview=in, :
void fun(in int x);
void fun(scope const int x);
- printf scanf
C99 7.19.6.1 printf 7.19.6.2 scanf.
printf , . , .
scanf .
:
- ,
- ,
- — , s
- C99
-, .
.
, printf/scanf, :
printf("%k\n", value);
const format = "%k\n";
printf(format.ptr, value);
— . ,
string s;
printf("%.*s\n", s.length, s.ptr);
printf("%d\n", s.sizeof);
ulong u;
scanf("%lld%*c\n", &u);
:
string s;
printf("%.*s\n", cast(int) s.length, s.ptr);
printf("%zd\n", s.sizeof);
ulong u;
scanf("%llu%*c\n", &u);
printf scanf pragma(printf) printf pragma(scanf) scanf.
, :
- extern (C ) extern (C++)
- const(char)*
- … -v , va_list ( «v» printf scanf)
.
«v»- .
- SOURCE_DATE_EPOCH
SOURCE_DATE_EPOCH. UNIX ( 1970-01-01 00:00:00), . DMD __DATE__, __TIME__ __TIMESTAMP__ .
指针的所有权/借用系统(也称为OB)确保取消引用的指针指向有效的内存对象。原型OB系统的范围
这是OB系统的原型,适用于D。最初,它仅用于指针,不适用于动态数组,类引用,集合中的引用或指针字段。添加这种支持会使实现复杂化,但不会改变其本质,因此,将其推迟到以后。RAII对象可以安全地管理自己的内存,因此它们不属于OB。不管采用哪种方法,无论指针是使用GC还是其他分配器分配内存,这对于OB都不重要,它们没有区别,并且处理相同。OB系统仅在使用@ live属性注释的功能中处于活动状态。它在语义处理之后仅用作检查是否违反有机物质规则。未添加新语法。不会对生成的代码进行任何更改。如果@直播函数调用不是函数@直播,预计这些所谓的功能将是一个在线- @兼容的接口,虽然它没有进行测试。如果非@ live函数调用@live函数,则传递的参数应遵循@live约定。OB系统检测到错误:- 取消引用处于无效状态的指针
- 指向一个可变内存对象的多个活动指针。
它不会检测到取消引用空指针或可能会引用空指针的尝试。这是行不通的,因为当前没有方法可以将类型注释为非空指针。OB的基本原理
OB设计遵循以下原则:对于每个内存对象,可以恰好存在一个指向它的变异指针,或几个非变异(只读)指针。设计
单个变异指针称为存储对象的“所有者”。他短暂地拥有一个内存对象,并且可以从中访问内存中的所有对象(即对象图)。由于它是指向此内存对象的唯一指针,因此它可以安全地管理内存(更改其形状,分配,释放和调整大小),而不会在其上可能存在的任何其他指针(可变或不可变)的脚下敲掉土壤(图形)内存)指示。如果有几个指向只读的内存对象图的指针,则它们可以安全地从中读取,而不必担心内存中对象图的突然更改。该技术的其余细节与指针如何变为只读和无效以及如何保持OB的核心原理有关。跟踪的指针仅跟踪在@live函数中声明为this,函数参数或局部变量的那些指针。其他功能的变量也不会被跟踪,即使@live也不会被跟踪,因为与其他功能的交互分析完全取决于该功能的签名,而不取决于其内部。不会跟踪const参数。指针状态每个指针都处于以下状态之一:未定义指针处于无效状态。取消引用这样的指针是一个错误。所有者所有者是指向内存中对象图的唯一指针。通常,指针-所有者没有作用域属性。如果使用不是从跟踪的指针派生的表达式初始化具有scope属性的指针,则它将成为所有者。如果将所有者指针分配给另一个指针-所有者,则第一个将进入未定义状态。借来的借用指针是暂时变为指向内存对象图的唯一指针的指针。他通过指针(所有者)的分配进入此状态,而所有者进入借款人的状态,直到借用指针的使用完成为止。借用的指针必须具有scope属性,并且是指向可变对象的指针。只读只读索引由所有者分配。只要“只读”指针处于活动状态,仍只能从此所有者分配“只读”指针。只读指针必须具有scope属性,并且也不能是指向可变对象的指针。一生“借用”或“只读”指示符的生命周期从第一次被取消引用的那一刻开始(而不是从其初始化或分配值的那一刻开始),直到该值最后被取消引用为止。它也被称为非词汇寿命。指针的状态转换执行以下操作之一时,指针将更改其状态:- 为它分配内存(例如,堆栈上的局部变量),这会将指针置于未定义状态
- 初始化(被视为分配)
- 分配-源指针和目标指针根据其所处的状态以及它们的类型和存储类来更改状态
- out ( ), , .
- ref , , .
- , .
- - ()
- , , .
- , ,
- , ,
- ,
作为原型,还有很多方面尚未考虑,直到原型表明这是一个可行的解决方案之前。错误期望很多错误。请向Bugzilla报告它们,并用关键字“ ob”标记。无需报告此处已经列出的其他限制。不会跟踪对类和关联数组的引用。假定它们由GC控制。
监视非所有者的借阅和所有者所有者是否受到泄漏的监视,但不监视其他指示器。如果借款人未使用指针初始化,则被视为所有者。@live void uhoh()
{
scope p = malloc();
scope const pc = malloc();
}
标记诸如范围之类的指针似乎没有意义,也许可以通过将其视为错误来解决。指针是由嵌套函数读取/写入的,不会被跟踪。@live void ohno()
{
auto p = malloc();
void sneaky() { free(p); }
sneaky();
free(p);
}
异常分析假定未引发异常。@live void leaky()
{
auto p = malloc();
pitcher();
free(p);
}
一种解决方案是使用范围(退出):@live void waterTight()
{
auto p = malloc();
scope(exit) free(p);
pitcher();
}
使用RAII对象或仅调用nothrow函数。惰性参数不考虑。二次复杂度分析表明二次复杂度,请尝试使@ live函数保持较小。混合不同的内存组组合不同的内存池:void* xmalloc(size_t);
void xfree(void*);
void* ymalloc(size_t);
void yfree(void*);
auto p = xmalloc(20);
yfree(p);
没有检测到。这可以通过使用特定于特定类型的池来避免:U* umalloc();
void ufree(U*);
V* vmalloc();
void vfree(V*);
auto p = umalloc();
vfree(p);
并可能禁止在@live函数中隐式转换为void *。可变函数的
参数可变函数的参数(例如printf)被视为已消耗。尽管这样做很安全,但似乎不太实用,可能需要进行审查。运行时更改
- TypeInfo_Class/TypeInfo_Interface.isBaseOf C#/Java isAssignableFrom.
TypeInfo_Class.isBaseOf true, , , , . isBaseOf, isAssignableFrom, , opAssign D — . TypeInfo_Interface.isBaseOf , TypeInfo_Class, TypeInfo_Interface. - core.memory.pageSize minimumPageSize.
pageSize .
import core.memory : pageSize;
ubyte[] buffer = new ubyte[pageSize];
minimumPageSize .
, . , . pageSize, .
, , , : ubyte[minimumPageSize].
import core.memory : minimumPageSize;
ubyte[minimumPageSize] buffer;
- Date.isoWeekYear Date.fromISOWeek std.datetime.date
ISO 8601 , Date and DateTime.
ISO , . Date.fromISOWeek(2020, 11, DayOfWeek.mon) Date(2020, 3, 9).
ISO , () .isoWeekYear Date ISO. , .isoWeekAndYear , . - std.xml .
std.xml . , , UndeaD. xml dub- dxml. - std.digest.digest .
2.076.1 . std.digest .
std.digest.digest 2.101.
Dub
- .
Posix , .dub. dub (, .swap.file.d), . , dub . , dub.
, . - Dub lint --report-file.
Dub lint --report-file: dub lint --report-file report.json