提问人:L. F. 提问时间:8/18/2019 更新时间:11/2/2019 访问量:349
在泛型编程中使用 placement new
Using placement new in generic programming
问:
在泛型代码中使用 placement new 在指定地址构造对象时,使用模式与通常的代码略有不同。例如,请考虑以下实现:([uninitialized.copy]uninitialized_copy
)
template <class It, class For>
For uninitialized_copy(It first, It last, For dest)
{
using T = typename std::iterator_traits<For>::value_type;
for (; first != last; ++first, (void)++dest)
::new (static_cast<void*>(std::addressof(*dest))) T(*first);
}
这篇文章从标准的角度解决了以下几点:
为什么使用而不仅仅是
::new
new
;为什么需要显式强制转换为。
void*
答:
(此答案使用 N4659,最终的 C++17 草案。
为什么使用而不仅仅是::new
new
::new
确保在全局范围内查找。相反,plain 首先在类的作用域中查找 if 是类类型(或其数组),然后才回退到全局作用域。根据 [expr.new]/9:operator new
new
T
如果 new-expression 以一元运算符开头,则 在全局范围内查找分配函数的名称。 否则,如果分配的类型是类类型或其数组, 分配函数的名称在 的作用域中查找。如果 此查找无法找到名称,或者如果分配的类型不是 类类型,则分配函数的名称在全局中查找 范围。
::
T
T
例如,使用
struct C {
void* operator new(std::size_t, void* ptr) noexcept
{
std::cout << "Hello placement new!\n";
return ptr;
}
};
plain 将导致找到此函数,从而打印不需要的消息,而仍将找到全局函数并正常工作。new
::new
由于 [new.delete.placement]/1,无法替换全局:operator new(std::size_t, void*)
这些函数是保留的;C++ 程序不能定义替换 C++ 标准库中的版本的函数 ([约束])。[basic.stc.dynamic] 的规定不适用 到这些保留的放置形式 和 .
operator new
operator delete
(有关重载的更多信息,请参阅如何编写符合 ISO C++ 标准的自定义 new 和 delete 运算符?operator new
为什么需要显式强制转换为void*
虽然全局不能被替换,但可以定义新版本。例如,假设以下声明放在全局作用域中:operator new(std::size_t, void*)
::operator new
void* operator new(std::size_t, int* ptr) noexcept
{
std::cout << "Hello placement new!\n";
return ptr;
}
然后会用这个版本代替全局版本,其中是一个值。显式转换指针,以确保 (我们打算调用的)版本在重载解析中获胜。::new(ptr) T
ptr
int*
void*
void*
operator new
来自评论:
但是,为什么我们要完全全球地称呼一些 类型本身有特殊的重载吗?看起来很正常 超载操作员更合适 - 为什么不合适?
new
void*
通常,用于分配目的。分配是用户应该控制的东西。用户可以为普通 .new
new
然而,在这种情况下,我们不想分配任何东西——我们只想创建一个对象!放置 new 更像是一种“黑客”——它的存在很大程度上是由于缺乏可用于在指定地址构造对象的语法。我们不希望用户能够自定义任何内容。然而,语言本身并不关心这个黑客——我们必须特别对待它。当然,如果我们有类似的东西(在 C++20 中出现),我们会使用它!construct_at
另请注意,这适用于最简单的情况,即您只想在原始分配空间中复制构造一系列对象。标准容器不仅允许您自定义元素的分配方式,还允许您通过分配器自定义元素的构造方式。因此,它们通常不用于其元素 - 它们称为 .此功能由 使用。std::uninitialized_copy
std::uninitialized_copy
std::allocator_traits<Allocator>::construct
std::scoped_allocator_adaptor
评论
new
new
评论