C++标准指的是术语"动态类型"(C标准在类似的上下文中指的是"有效类型"),例如
如果程序尝试通过以下类型之一以外的 glvalue 访问对象的存储值,则行为是未定义的:
- 对象的动态类型,
但是,如何确定分配malloc
对象的动态类型呢?
例如:
void *p = malloc(sizeof(int));
int *pi = (int*)p;
pi
指向的对象动态类型是否会int
?
根据C++规范:
动态类型:
派生最多的对象 (1.8) 的类型,glvalue 表达式表示的 glvalue 所指的类型
malloc
的返回值是未初始化的存储块。该存储中未构造任何对象。因此它没有动态类型。
void*
不指向对象,只有对象具有动态类型。
您可以通过开始对象的生存期在该存储中创建对象。但在你这样做之前,它只是存储。
在 C 中,有效类型仅在访问对象时才相关。然后由
- 声明类型(如果有)
- 它是其副本的另一个对象的类型(例如。
memcpy
) - 访问它的左值的类型,例如,如果将
void*
转换为另一种指针类型(例如int*
),然后取消引用。
后者通常是malloc
ed 对象发生的情况,如果将 malloc
的返回值分配给指针类型。
动态类型是一个正式术语,用于描述本质上的多态对象,即具有至少一个virtual
函数的对象。因此这是一个C++术语,例如C没有virtual
的概念。
但是如何使用malloc分配对象的动态类型 确定?
其实不然。 malloc
分配N
原始内存字节并通过void*
返回 - 推断正确的类型是你的工作。此外,此内存仅表示放置对象的区域,但在显式调用其构造函数之前,此对象不会处于活动状态。(再次,从C++的角度来看)
pi 指向的对象动态类型会是 int 吗?
否,因为在描述具有类类型的对象时,术语动态类型是有意义的。 int
不是,也不可能。
class Foo
{
//virtual ~Foo() = default;
virtual void f() {}
};
class Bar : public Foo
{
virtual void f() {}
};
// ...
Foo *ptr = new Bar();
这里Foo
是ptr
的静态类型,而Bar
是其动态类型。
现状是malloc
不创建对象。唯一这样做的构造是new
表达式、定义、强制转换和变量成员赋值。有关此内容的正确措辞,请参阅P0137R0。
如果要使用由 malloc
生成的存储,假设它已正确对齐(除非使用扩展对齐,否则情况如此),请调用放置 new:
auto p = malloc(sizeof(int));
int* i = new (p) int{0};
// i points to an object of type int, initialized to zero
因此,在C++中使用malloc是毫无用处的,因为沼泽标准new
有效地将上述步骤组合为一个。
另见@T.C.在提问者相关问题中的回答。
根据 C++11 标准中的 1.3.7
,动态类型 最派生对象的 glvalue 类型 (1.8),GLvalue 表达式表示的 GLVALUE 所指的 GLVALUE 类型 [示例:如果静态类型为"指向类 B"的指针 (8.3.1) p 指向类的对象 D,派生自 B(条款 10),表达式 *p 的动态类型为"D"。处理引用 (8.3.2) 同样地。— 结束示例 ]
举个例子
class A {}
class B : public A {}
A *a = new B;
a
的"静态"类型A *
,而其动态类型为B *
。
引用不同类型的想法是为了防止类似
class A{}
class B : public A {int x;}
class C : public A {int y;}
A *a = new B;
reinterpret_cast<C *>(a)->x;
这可能会导致未定义的行为。
void *
不指向对象,但动态类型和声明类型之间的区别仅对对象有意义。