【发布时间】:2018-09-07 20:40:53
【问题描述】:
学究式,这可能不太好。根据cppref:
如果表达式是其他任何东西,包括如果它是通过new-expression的数组形式获得的指针,则行为未定义。
抛开这一点,下面的代码在实践中是否可行(T 是非数组,并假设 new 未被替换)?
auto p = (T*)operator new(sizeof(T));
new(p) T{};
delete p;
据说在cppref那个
调用分配函数时,new-expression 传递 作为第一个参数请求的字节数,类型
std::size_t,也就是非数组 T 的sizeof(T)。
所以我想这可能没问题。不过也有说从C++14开始,
允许新表达式省略或合并分配 通过可替换的分配函数。在省略的情况下, 存储可以由编译器提供而无需调用 分配函数(这也允许优化未使用的 新表达式)。在合并的情况下,由 a 进行的分配 new-expression E1 可以扩展为提供额外的存储 如果以下所有条件都为真,则另一个新表达式 E2:[...]
请注意,这种优化只在 new-expressions 是允许的 使用,而不是任何其他方法来调用可替换的分配函数:
delete[] new int[10];可以优化,但operator delete(operator new(10));不能。
我不太确定其中的含义。那么,这在 C++14 中可以吗?
我为什么要问这个问题? (source)
有时,内存分配和初始化不能一步完成。 您必须手动分配内存,执行其他操作,然后初始化对象, 例如,提供强大的异常安全性。 在这种情况下,如果不能在结果指针上使用 delete 表达式,则必须手动取消初始化和解除分配,这很繁琐。 更糟糕的是,如果同时使用新的表达方式和手动方法, 您必须跟踪每个对象使用了哪一个。
【问题讨论】:
-
在您到达
delete之前,您必须确保您的placement new 使用适当对齐的内存,在这种情况下不会发生这种情况。 -
@SamVarshavchik 它确实发生了。
operator new()保证这一点。 此函数需要返回一个适当对齐的指针以保存任何基本对齐的对象。请参阅here。 -
“实际上可以吗”很难回答;您似乎同意代码是未定义的行为,因此您确实要求调查所有存在的编译器如何表现出这种未定义的行为。此外,它们可能会在未来的编译器版本或模式中以不同的方式表现出来。
-
我想知道你为什么还要问。如果你不这样做,你不应该这样做,你永远不必找到答案,处理错误报告,重写整个事情,当它不适用于一些新的平台甚至一些新的编译器版本,...
-
@Lingxi 从技术上讲,使用您编写的代码,
p并不指向新构造的T。内存地址是相同的,但编译器可以假定它引用了在放置new之前存在的(不存在的)T。在这么简单的代码中,我认为不会有什么不同,但如果T有一个const成员或其他东西,编译器可能会在调用new之前从内存中加载它。std::launder调用告诉它不要进行这种优化,但是将放置的结果new分配回p会更容易和更清晰。
标签: c++ c++14 new-operator dynamic-memory-allocation delete-operator