这个程序没有很好的定义。
trivial destructor
(见
this
return std::shared_ptr<T>(new (memory.release()) T());
是
对的它省略了
sizeof(T)
std::byte
T
在记忆中,这是美好的,然后当
shared_ptr
准备删除时,它会调用
delete this->get();
,这是错误的。这首先解构了
,但随后它会释放一个
而不是
std::byte[]
,这将
可能
C++标准符号:85.2.4p8[ Exp.New ]
新表达式可以通过调用分配函数来获取对象的存储。[…]如果分配的类型是数组类型,则分配函数的名称为
operator new[]
.
新操作员[]
new
只发生一次
make_unique
以及同一节的第11部分:
当新表达式调用分配函数且该分配尚未扩展时,新表达式将请求的空间量作为类型的第一个参数传递给分配函数
std::size_t
. 该参数不得小于所创建对象的大小;仅当对象是数组时,它可能大于正在创建的对象的大小。对于数组
char
unsigned char
和
,新表达式的结果与
函数被假定为返回指向存储的指针,这些指针对于具有基本对齐方式的任何类型的对象都是适当对齐的,这种对数组分配开销的约束允许使用分配的常见习惯用法
其他类型的对象稍后将放置到的字符数组中。[完注]
如果您阅读§21.6.2[新建.删除.数组],您会看到默认
新操作员[]
operator delete[]
operator new
和
operator delete
,问题是我们不知道传递给它的大小,它是
可能
delete ((T*) object)
调用(以存储大小)。
查看删除表达式的作用:
§8.5.2.5p8[解释删除]
[…]delete表达式将为要删除的数组的[…]元素调用析构函数(如果有)
p7.1
如果未忽略要删除对象的新表达式的分配调用[…],则删除表达式应调用解除分配函数(6.6.4.4.2)。新表达式的分配调用返回的值应作为第一个参数传递给释放函数。
自从
std::字节
delete[]
,因为它除了调用deallocate函数之外不会执行任何操作(
运算符删除[]
).我们只需要重新解释一下
std::byte*
,我们会得到什么
new[]
另一个问题是,如果
T
投掷。一个简单的修复方法是放置
而内存仍由
std::unique_ptr
删除[]
正确地
T* ptr = new (memory.get()) T();
memory.release();
return std::shared_ptr<T>(ptr, [](T* ptr) {
ptr->~T();
delete[] reinterpret_cast<std::byte*>(ptr);
});
刚出现的
生命周期结束
sizeof(T)
std::字节
开始一个新的生命
然后,当它被删除时
通过显式调用析构函数结束,然后根据上面的说明,delete表达式取消分配存储。
这导致了以下问题:
如果存储类不是
std::字节
,并不是微不足道的破坏?例如,我们使用一个非平凡的联合作为存储。
使命感
delete[] reinterpret_cast<T*>(ptr)
将对非对象的对象调用析构函数。这显然是未定义的行为,符合§6.6.3p6[基本寿命]
可以使用,但只能以有限的方式使用。[…]如果:对象将是或曾经是具有非平凡析构函数的类类型,并且指针用作删除表达式的操作数,则程序具有未定义的行为
所以要像上面那样使用它,我们必须构造它,只是为了再次破坏它。
默认构造函数可能工作正常。通常的语义是“创建一个可以被破坏的对象”,这正是我们想要的。使用
std::uninitialized_default_construct_n
ptr->~T();
auto* as_storage = reinterpret_cast<StorageClass*>(ptr);
std::uninitialized_default_construct_n(as_storage, n);
delete[] as_storage;
新接线员
和
运算符删除
static void byte_deleter(std::byte* ptr) {
return ::operator delete(reinterpret_cast<void*>(ptr));
}
auto non_zero_memory(std::size_t size)
{
constexpr std::byte non_zero = static_cast<std::byte>(0xC5);
auto memory = std::unique_ptr<std::byte, void(*)(std::byte*)>(
reinterpret_cast<std::byte*>(::operator new(size)),
&::byte_deleter
);
std::fill(memory.get(), memory.get()+size, non_zero);
return memory;
}
template <class T>
auto on_non_zero_memory()
{
auto memory = non_zero_memory(sizeof(T));
T* ptr = new (memory.get()) T();
memory.release();
return std::shared_ptr<T>(ptr, [](T* ptr) {
ptr->~T();
::operator delete(ptr, sizeof(T));
// ^~~~~~~~~ optional
});
}
但这看起来很像
std::malloc
和
std::free
.
std::aligned_storage
与给定的类型相同
刚出现的
std::字节
因为对齐存储是一个微不足道的聚合。