在泛型编程中使用新的放置
Using placement new in generic programming
当在通用代码中使用放置新内容在指定地址构造对象时,使用模式与通常的代码略有不同。 例如,考虑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
可确保在全局范围内查找operator new
。 相反,如果纯new
是类类型(或其数组(,则T
首先在类的作用域中查找,然后才回退到全局作用域。 根据 [expr.new]/9:
如果new-表达式以一元运算符开头
::
则 分配函数的名称在全局范围内查找。 否则,如果分配的类型是类类型T
或其数组, 分配函数的名称在T
范围内查找。如果 此查找无法找到名称,或者如果分配的类型不是 类类型,分配函数的名称在全局中查找 范围。
例如,与
struct C {
void* operator new(std::size_t, void* ptr) noexcept
{
std::cout << "Hello placement new!n";
return ptr;
}
};
纯new
将导致找到此函数,从而打印不需要的消息,而::new
仍将找到全局函数并正常工作。
由于 [new.delete.placement]/1,无法替换全局operator new(std::size_t, void*)
:
这些函数是保留的;C++程序不能定义替换C++标准库中版本的函数。 ([约束](。[basic.stc.dynamic] 的规定不适用 到这些保留的
operator new
和operator delete
的安置形式.
(有关重载operator new
的详细信息,请参阅如何编写符合 ISO C++ 标准的自定义新建和删除运算符?
为什么需要显式强制转换为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*
,以确保operator new
的void*
版本(我们打算称之为(在重载分辨率中获胜。
来自评论:
但是,如果某些人,我们为什么要为
void*
调用确切的全球new
类型对自己有特殊的新过载吗?看起来很正常 重载运算符更合适 - 为什么不合适?
通常,new
用于分配目的。 分配是用户应该控制的内容。 用户可以为普通new
推出更合适的版本。
但是,在这种情况下,我们不想分配任何东西 — 我们要做的就是创建一个对象! 放置 new 更像是一种"黑客"——它的存在主要是由于缺乏可用于在指定地址构造对象的语法。 我们不希望用户能够自定义任何内容。 然而,语言本身并不关心这个黑客 - 我们必须特别对待它。 当然,如果我们有类似construct_at
的东西(即将推出 C++20(,我们将使用它!
另请注意,std::uninitialized_copy
适用于最简单的情况,即您只想在原始分配的空间中复制构造一系列对象。 标准容器不仅允许您通过分配器自定义元素的分配方式,还允许您自定义元素的构造方式。 因此,他们通常不对他们的元素使用std::uninitialized_copy
——他们称之为std::allocator_traits<Allocator>::construct
. 此功能由std::scoped_allocator_adaptor
使用。
- 使用泛型编程的基本数据结构
- 在泛型编程中使用新的放置
- 在泛型编程中选择类型参数
- 在泛型编程C++重载增量运算符
- 处理C++泛型编程中的空分配
- 有关C++泛型编程的错误
- 在泛型编程中,需要在派生类中重新声明基类成员函数
- 将泛型编程与多态性混合在一起
- C++泛型编程 CRTP 基类继承自派生类型提供的类
- 泛型编程中带有关键字模板的规范
- 为什么泛型编程设计更喜欢自由函数而不是成员函数
- c++如何在泛型编程中声明自定义数组
- C++函数式和泛型编程[使用MySQL连接器示例]
- 继承和虚函数与泛型编程
- 虚函数与泛型编程
- 只使用<泛型编程中的比较
- c++泛型编程与模板和nullptr
- c++中的泛型编程和类中的类型定义
- 如何在c++中使用泛型编程来代替多态性
- 概念与复制构造函数冲突的泛型编程