C++ 使用calloc';将内存作为类型化数组,而不使用UB

C++ 使用calloc';将内存作为类型化数组,而不使用UB,c++,optimization,undefined-behavior,strict-aliasing,C++,Optimization,Undefined Behavior,Strict Aliasing,我需要构造一个大型动态大小的数组,类型为T,它有一个全零位模式作为默认构造值的表示。实际上,在我的应用程序中,默认情况下构造每个元素,如std::vector(有效地将内存设置为零)会产生可测量的开销 我想使用calloc来代替操作系统的零页面。我不能简单地将返回的内存强制转换为T*,因为在该内存中从未构造过T,违反了严格的别名规则并导致未定义的行为(请参阅) 在calloced内存中使用placement new可以正确地通过Clang 9和gcc trunk进行优化,但不能通过gcc的发布版

我需要构造一个大型动态大小的数组,类型为
T
,它有一个全零位模式作为默认构造值的表示。实际上,在我的应用程序中,默认情况下构造每个元素,如
std::vector
(有效地将内存设置为零)会产生可测量的开销

我想使用
calloc
来代替操作系统的零页面。我不能简单地将返回的内存强制转换为
T*
,因为在该内存中从未构造过
T
,违反了严格的别名规则并导致未定义的行为(请参阅)

在calloced内存中使用placement new可以正确地通过Clang 9和gcc trunk进行优化,但不能通过gcc的发布版本或任何MSVC版本进行优化(请参阅)


有什么方法可以可靠地删除这里的memset吗?

不确定它是否真的符合要求,但可能会有所帮助?据我所知,std::launder只在对象生命周期方面有帮助,例如,在使用新的放置方式覆盖包含常量属性的对象时。您仍然需要传入一个
T*
,如果不引入UB,我无法构造它。@Fabian Knorr可测量的开销真的那么大吗?如果您真的想这样做,可以将逻辑隔离到一个小cpp文件中,在禁用严格别名优化的情况下编译该文件,然后使用Godbolt查看生成的代码。你会有好朋友的,好吧,Linux内核仍然禁用严格的别名优化,尽管是针对普通的C.@ErikAlapä:别名规则的编写是基于这样的假设,即用于各种目的的实现能够识别对这些目的有用的构造,这将被视为实现质量问题。这些规则旨在迫使程序员生成较慢代码的神话是荒谬的,但似乎是不可动摇的。@supercat:当然,这些规则并非旨在迫使程序员生成较慢的代码。但有时,我想用C或C++作为一个可移植的汇编程序,而不是编译器第二个猜想。请看10-15年前Linux Torvald与gcc开发人员就别名问题进行的严格辩论,了解更多内容。不确定它是否真的符合要求,但可能会有所帮助?据我理解,std::launder仅在对象生命周期方面有所帮助,例如,在使用新的位置覆盖包含常量属性的对象时。您仍然需要传入一个
T*
,如果不引入UB,我无法构造它。@Fabian Knorr可测量的开销真的那么大吗?如果您真的想这样做,可以将逻辑隔离到一个小cpp文件中,在禁用严格别名优化的情况下编译该文件,然后使用Godbolt查看生成的代码。你会有好朋友的,好吧,Linux内核仍然禁用严格的别名优化,尽管是针对普通的C.@ErikAlapä:别名规则的编写是基于这样的假设,即用于各种目的的实现能够识别对这些目的有用的构造,这将被视为实现质量问题。这些规则旨在迫使程序员生成较慢代码的神话是荒谬的,但似乎是不可动摇的。@supercat:当然,这些规则并非旨在迫使程序员生成较慢的代码。但有时,我想用C或C++作为一个可移植的汇编程序,而不是编译器第二个猜想。看一看10-15年前LinuxTorvald与gcc开发人员就别名问题进行的严格辩论,了解更多的上下文。