#include <cstdlib>
struct X { int a, b; };
X *make_x() {
// The call to std::malloc implicitly creates an object of type X
// and its subobjects a and b, and returns a pointer to that X object
// (or an object that is pointer-interconvertible ([basic.compound]) with it),
// in order to give the subsequent class member access operations
// defined behavior.
X *p = (X*)std::malloc(sizeof(struct X));
p->a = 1;
p->b = 2;
return p;
}
2条答案
按热度按时间tct7dpnv1#
这是法律的,因为C20。在此之前,它在技术上是非法的,但无论如何,在实践中工作。
这通常是UB,因为在生命周期开始之前访问对象,但C20添加了
[intro.object]/11
:某些操作被描述为在指定的存储区域内 * 隐式创建对象 *。对于被指定为隐式创建对象的每个操作,该操作隐式创建并启动零个或多个隐式生存期类型的对象的生存期([basic.types.general])如果这样做将导致程序具有定义的行为,则在其指定的存储区域中。如果没有这样的对象集将给予程序定义的行为,程序的行为是未定义的。2如果多个这样的对象集将给予程序定义的行为,则不指定创建哪一个这样的对象集。
malloc()
在[c.malloc]/4
中得到了祝福:这些函数在返回的存储区域中隐式地创建对象([intro.object]),并返回一个指向合适的创建对象的指针。在calloc和realloc的情况下,对象分别在存储置零或复制之前创建。
(Note“返回一个指向合适的创建对象的指针”,否则需要
std::launder()
。这适用于“隐式生存期类型”:
[basic.types.general]/9
标量类型、隐式生存期类类型([class.prop])、数组类型和这些类型的cv限定版本统称为隐式生存期类型。
[class.prop]/9
个一个类S是一个隐生存期类,如果
(9.1)- 它是一个聚合,其析构函数不是用户提供的,或者
(9.2)- 它至少有一个平凡的合格构造函数和一个平凡的非删除析构函数。
(9.1)这听起来令人困惑,直到你读到“注4”在第一个报价在这个答案。
csga3l582#
从C++20开始,这一点就按照intro.object#11进行了很好的定义。该标准甚至有一个类似的例子,其中从
std::malloc
获得的指针被解引用。从介绍对象:
[示例]
字符串
结束示例]