微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

双重构造是不确定的行为吗?

如何解决双重构造是不确定的行为吗?

在我们的代码库中,使用了一个内存块池,并且在“分配”之后,使用“ placement new”构造了对象。但是我缺少析构函数调用,发现允许“双重构造”很奇怪,并且想知道再次在同一对象上调用构造函数是否是未定义的行为。

在C ++ 11 3.8.4 [basic.life]中,它读取为

程序可以通过重用对象占用的存储空间或通过终止对象的生命周期来结束 为具有非平凡析构函数的类类型的对象显式调用析构函数。对于物体 具有非平凡析构函数的类类型,则不需要程序显式调用析构函数 在对象占用的存储空间被重用或释放之前;但是,如果没有显式调用 析构函数,或者如果不使用delete-expression(5.3.5)释放存储,则析构函数不得为 隐式调用,并且依赖于析构函数产生的副作用的任何程序均未定义 行为。

这是否意味着只要我们讨论具有析构函数且没有副作用的类型,就可以错过析构函数调用吗?

编辑:上下文是:不带堆的嵌入式SW,自己的容器实现在c-array-elements或byte-arrays上进行新的放置。

解决方法

您可以在没有UB的情况下进行双重构建。新对象是一个完全不同的对象,在指向旧对象的指针/引用之后是UB。

在进行新的放置时,很容易越过UB,更不用说双重构造了。

不调用析构函数仅表示未清除对象。如果析构函数是微不足道的,则不会有太大的风险。像调用析构函数一样,在另一个对象上构造一个对象会终止对象的生存期。

如果对象以适当的类型自动存储,则在其上构造一个不同的对象并退出范围(导致不再存在的原始对象被销毁)通常是UB(在这里可以使用琐碎的析构函数来避免UB)原始对象;这就是为什么字节缓冲区可以在其中进行新的放置的原因。

,

This answer已经很好地回答了这个问题。

尽管,我要补充一点,在生产代码中使用 placement new 通常是一种不好的做法,容易出错和/或出错。存在许多出色的替代方案(包括某些库)。因此,您应该寻找更简单的选择(可以像使用std::vector一样简单-如果绝对需要,请调用reserve()!)-有时,首先在代码库中使用和引入新的放置方法是经常会被误导,遗留或有时过早优化。

尽管很难给出具体建议-一种方法可能是删除新的放置位置或用某种标准容器替换放置位置-然后检查是否出现任何问题(通常是性能问题)。

根据我的经验,仅删除旧版代码中新放置的位置不会导致任何问题,因为(可能)用于修复的性能问题已被广泛的“系统”优化(从c ++级别降到严格级别)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。