【发布时间】:2019-03-20 02:27:12
【问题描述】:
考虑以下示例:
#include <array>
#include <memory>
class trivial
{
public:
trivial() = default;
trivial(int a, float b) : m_a(a), m_b(b) {}
private:
int m_a;
float m_b;
};
template<typename T>
void write(T& arr, size_t idx, int a, float b)
{
::new(static_cast<void*>(std::addressof(arr[idx]))) trivial(a, b);
}
template<typename T>
void destroy(T& arr, size_t idx)
{
std::destroy_at(std::addressof(arr[idx]));
}
int main()
{
auto arr = std::array<trivial, 20>();
write(arr, 3, 10, 20.0f);
destroy(arr, 3);
}
对任意(但合理的)数据数组使用就地放置new 和std::destroy_at 是否安全?这里是否存在任何风险或潜在的未定义行为,或可移植性问题?假设我们不会尝试分配一个被破坏的值,我理解它是未定义的。
我注意到这种方法的基准测试比使用std::aligned_storage 和reinterpret_cast 更好,主要是因为std::launder 充当了优化阻止程序。如果我对将值存储在 std::array 中的额外限制感到满意(例如需要默认构造函数),这是一个可接受的用例吗?
【问题讨论】:
-
你有双重毁灭。当
arr超出范围时,它会破坏它的所有元素,包括你在上面调用destroy_at的那个。我认为它是 UB,但不是 100% 确定(这里的析构函数是微不足道的)。
标签: c++ c++17 destructor memory-alignment placement-new