简体   繁体   English

为什么在c ++ 17中不推荐使用std :: allocator的构造和销毁函数?

[英]Why are are std::allocator's construct and destroy functions deprecated in c++17?

The c++17 specification deprecates the construct and destroy members of the std::allocator object. c ++ 17规范弃用了constructdestroystd::allocator对象的成员。 The working group provided rationale for deprecating other member functions here , under the heading "Deprecate the redundant members of std::allocator". 用于弃用其他成员函数工作组提供的基本原理这里 ,标题下的“弃用的std ::分配器的所述冗余成员”。

However they don't mention specifically why those two members are deprecated or what the recommendation is for replacing that functionality. 但是,他们没有具体提到为什么这两个成员被弃用或者建议取代该功能的原因。 I'm assuming the implication is to use std::allocator_traits::construct instead. 我假设暗示是使用std::allocator_traits::construct代替。

I'm a bit confused about whether implementing construct may actually still be necessary in some cases though because of this comment about std::allocator_traits::construct 在某些情况下,由于关于std::allocator_traits::construct注释,我是否真的仍然需要实现construct我有点困惑

Because this function provides the automatic fall back to placement new, the member function construct() is an optional Allocator requirement since C++11. 因为此函数提供自动回退到placement new,所以成员函数construct()是自C ++ 11以来的可选Allocator要求。

For custom allocators (eg for page-aligned memory using memalign ), will falling back to placement new always produce the correct behavior? 对于自定义分配器(例如,对于使用memalign页面对齐的内存),将回退到new位置总会产生正确的行为吗?

The allocator requirements table says that construct(c, args) , if provided, must "construct an object of type C at c ". 分配器要求表construct(c, args) ,如果提供,必须“在c处构造一个C类型的对象”。

It says absolutely nothing about 1) what arguments are to be passed to C 's constructor or 2) how these arguments are to be passed. 它绝对没有说明1)将哪些参数传递给C的构造函数或2)如何传递这些参数。 That's the allocator's choice, and in fact two allocators in the standard do mess with the arguments before passing them to C 's constructor: std::scoped_allocator_adaptor and std::pmr::polymorphic_allocator . 这是分配器的选择,实际上标准中的两个分配器在将它们传递给C的构造函数之前会搞乱参数: std::scoped_allocator_adaptorstd::pmr::polymorphic_allocator When constructing a std::pair , in particular, the arguments they pass to pair 's constructor may not even resemble the ones they received. 特别是在构造std::pair ,它们传递给pair的构造函数的参数可能与它们收到的参数不同。

There's no requirement to perfectly forward, either; 也没有要求完美转发; a C++03-style construct(T*, const T&) is conforming if inefficient. 如果效率低下construct(T*, const T&) C ++ 03风格的construct(T*, const T&)是符合要求的。

std::allocator 's construct and destroy are deprecated because they are useless: no good C++11 and later code should ever call them directly, and they add nothing over the default. std::allocatorconstructdestroy被弃用了,因为它们没用:没有好的C ++ 11和更高版本的代码应该直接调用它们,并且它们在默认情况下不添加任何东西。


Handling memory alignment should be the task of allocate , not construct . 处理内存对齐应该是allocate而不是construct的任务。

The functions were removed along with others from the paper D0174R0 Deprecating Vestigial Library Parts in C++17 . 这些功能与C ++ 17中的D0174R0 Deprecating Vestigial Library Parts中的其他功能一起被删除。 If we look at the relevant section we have 如果我们看一下我们的相关部分

Many members of std::allocator redundantly duplicate behavior that is otherwise produced by std::allocator_traits<allocator<T>> , and could safely be removed to simplify this class. std :: allocator的许多成员冗余地重复由std::allocator_traits<allocator<T>>产生的行为,并且可以安全地删除以简化此类。 Further, addressof as a free function supersedes std::allocator<T>::address which requires an allocator object of the right type. 此外,作为自由函数的地址取代了std::allocator<T>::address ,它需要一个正确类型的分配器对象。 Finally, the reference type aliases were initially provided as an expected means for extension with other allocators, but turned out to not serve a useful purpose when we specified the allocator requirements (17.6.3.5 [allocator.requirements]). 最后,引用类型别名最初是作为与其他分配器进行扩展的预期方式提供的,但在我们指定分配器要求时(17.6.3.5 [allocator.requirements])结果证明它没有用处。

While we cannot remove these members without breaking backwards compatibility with code that explicitly used this allocator type, we should not be recommending their continued use. 虽然我们无法在不破坏与显式使用此分配器类型的代码的向后兼容性的情况下删除这些成员,但我们不应该建议继续使用它们。 If a type wants to support generic allocators, it should access the allocator's functionality through allocator_traits rather than directly accessing the allocator's members - otherwise it will not properly support allocators that rely on the traits to synthesize the default behaviors. 如果某个类型想要支持通用分配器,它应该通过allocator_traits访问分配器的功能,而不是直接访问分配器的成员 - 否则它将不能正确支持依赖于特征来合成默认行为的分配器。 Similarly, if a user does not intend to support generic allocators, then it is much simpler to directly invoke new, delete, and assume the other properties of std::allocator such as pointer-types directly. 类似地,如果用户不打算支持泛型分配器,那么直接调用new,delete和直接假设std :: allocator的其他属性(如指针类型)要简单得多。

Emphasis mine 强调我的

So the rational was we do not need to duplicate all of the code in allocator since we have the allocator traits. 所以理性的是我们不需要复制分配器中的所有代码,因为我们有分配器特性。 If we look at std::allocator_traits we will see that it does have 如果我们看一下std::allocator_traits我们会看到它确实有

allocate
deallocate
construct
destroy
max_size

static functions so we can use those instead of the ones in the allocator. 静态函数,所以我们可以使用那些而不是分配器中的那些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM