malloc分配的对象的动态类型是什么?

7
C++标准中提到了“动态类型”这个术语(C标准在类似的上下文中提到了“有效类型”),例如:
如果程序尝试通过除以下类型之一的glvalue访问对象的存储值,则行为未定义: - 对象的动态类型,
但是,使用malloc分配对象的动态类型如何确定呢?
例如:
void *p = malloc(sizeof(int));
int *pi = (int*)p;

pi所指向的对象的动态类型将会是int吗?


2
我认为你的假设是错误的,在C语言中似乎不存在这个术语。也许你指的是“有效类型”?此外,我认为这些事情的规则在C和C++中可能会有很大不同,所以最好分别提出两个问题。 - Jens Gustedt
1
@JensGustedt 您是正确的,这在C语言中被称为“有效类型”。 - vitaut
https://dev59.com/xmvXa4cB1Zd3GeqPL7RP - Jiminion
2
@vitaut:术语“有效类型”和“动态类型”完全没有任何关系。 - Nicol Bolas
1
@M.M:但是现在还没有“类型为T的对象”。你从哪里得到了floatint?它们不是malloc调用的一部分。这里只有存储空间而没有对象。所有对象都需要存储空间,但并非所有存储空间都需要对象。 - Nicol Bolas
显示剩余17条评论
5个回答

8
根据C++规范: 动态类型: 指由glvalue表达式所表示的glvalue引用的最派生对象(1.8)的类型。
malloc的返回值是未初始化存储块。没有任何对象在该存储中构建,因此它没有动态类型。 void*不指向对象,只有对象才有动态类型。 您可以通过开始其生命周期,在该存储中创建一个对象。但在这样做之前,它只是存储。

谢谢。那么我的例子呢?pi所指向的对象会有动态类型int吗? - vitaut

5
在C语言中,有效类型只在访问对象时才相关。然后它由以下方式决定:
  • 声明类型(如果有)
  • 另一个对象的类型,该对象是它的副本(例如,memcpy
  • 通过其进行访问的lvalue的类型,例如如果将void*转换为另一种指针类型(例如int*),然后对其进行解引用。
通常情况下,使用malloc分配的对象会发生后一种情况,如果将malloc的返回值赋给指针类型。

在C++中,也就是这个问题所涉及的内容,malloc不会创建对象。仅仅通过int来别名化它产生的原始存储空间是完全无意义的。 - Columbo
1
@Columbo,当我回答这个问题时,它也被标记为C。 - Jens Gustedt

3

动态类型是一个正式术语,用于描述本质上是多态对象的东西,即具有至少一个虚函数的对象。因此,这是一个C++术语,例如C没有虚拟概念。

但是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();

在这里,ptr的静态类型是Foo,而其动态类型是Bar

2
我认为这不正确,因为在标准中,“动态类型”似乎包括原始类型。 - vitaut
@vitaut:仅在技术上,它才包括非虚拟类型。非虚拟类型的动态类型是其本身。 - Nicol Bolas
1
动态类型 <glvalue>指代由glvalue表达式所引用的最派生对象(1.8)的类型。 [例如:如果一个静态类型为“指向类B的指针”(8.3.1)的指针p指向从B(第10章)派生出来的类D的对象,则表达式*p的动态类型为“D”。参考文献(8.3.2)处理方式相似。——示例结束] - ftynse
如果你指的是“有效类型”,那么它就是“int”。 - edmz
1
@vitaut:我知道这些术语看起来可能有关联,但实际上它们并不是完全相关的;如果您有建议可以使这更清晰,请告诉我。 - edmz
1
C++标准不使用“有效类型”这个术语。 - vitaut

3
现状是 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.'s answer

0
根据C++11标准中的1.3.7,
动态类型是指由glvalue表达式所表示的glvalue对象(1.8)中最派生的对象的类型。 [例如:如果一个静态类型为“指向类B的指针”(8.3.1)的指针p指向从B(第10条)派生出来的类D的对象,则表达式*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 * 不指向对象,但动态类型和声明类型之间的区别仅对对象有意义。


谢谢您提供标准报价,但是malloc的结果怎么样呢?pi指向的对象是否具有动态类型int? - vitaut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接