如果琐碎的默认构造函数不执行任何操作,为什么不能使用malloc创建琐碎的可构造对象?


14

我很难理解cppreference引用的有关普通默认构造函数的以下段落。我已经搜索了stackoverflow,但仍然没有一个明确的答案。所以请帮忙。

普通的默认构造函数是不执行任何操作的构造函数。与C语言兼容的所有数据类型(POD类型)都是默认可构造的。但是,与C语言不同,不能通过简单地重新解释适当对齐的存储来创建具有琐碎默认构造函数的对象,例如,用std :: malloc分配的内存:正式引入新对象并避免潜在的未定义行为时,需要placement-new。

具体来说,如果琐碎的默认构造函数什么都不做,为什么我们不能重新解释存储并假装存在具有给定类型的对象?您能否提供一些可能导致未定义行为的示例?


编译器最重要的工作不是编译源代码,而是拒绝可能无效的代码。当您使用malloc()时,它无法做到这一点。
汉斯·帕桑

6
原因很简单。程序员做疯狂事情的​​机会越少,编译器做疯狂事情的​​机会就越多(积极的优化)。
n。代词

1
由于类似的原因,你不能只是*reinterpret_cast<float*>(&someNonFloatObject) = 0.1f;。C ++具有在抽象机上指定的对象和对象生存期的概念,并且仅仅因为没有CPU指令可以从存储中创建对象,并不意味着抽象机上没有任何区别。
Max Langhof

1
@HansPassant拒绝所有代码的编译器将拒绝所有无效代码。无论如何,拒绝具有UB的程序不是编译器的工作。
n。代词

Answers:


7

P0593R5给出了以下示例:

struct X { int a, b; };
X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}

并说明:

当使用C ++编译器编译时,此代码具有未定义的行为,因为p-> a尝试写入X对象的int子对象,并且该程序从未创建X对象或int子对象。

每个[介绍对象] p1,

当隐式更改联合的活动成员或创建临时对象时,将通过定义,new-expression创建对象。

...并且该程序没有执行这些操作。

实际上,这是可行的,并且UB情况比其他任何情况都更多地被视为标准中的缺陷。本文的整个目标是提出一种解决该问题和类似案例而不破坏其他事物的方法。


1

出于“纯度”的原因。

替代方案和实际状态是,每个存储区域将同时包含适合该存储的所有对象。一些委员会成员对现状感到不安,许多人担心在同一位置(处于虚拟,未初始化状态)拥有无限多个对象的想法。

没有人能够在存储区域中拥有无限多个对象的情况下显示出逻辑问题。

因为他们在标准的不同部分说到矛盾的事物,委员会成员才决定认真对待标准中最糟糕的部分之一。

另外,如果您真的很重视标准的这一部分,则严格禁止使用字符串文字。


严格禁止使用字符串文字。关于type_info对象,存在类似的CWG问题。您是否报告过“回合字符串文字”?
语言律师,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.