#include <iostream>
#include <vector>
#include <memory_resource>
class SpecialMemoryResource : public std::pmr::memory_resource
{
public:
void* do_allocate(std::size_t bytes, std::size_t alignment) override { return nullptr; }
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {}
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
return &other == this;
}
};
static auto k_SpecialMemoryResource = SpecialMemoryResource{};
bool isUsingSpecialMemoryResource(const std::pmr::vector<int>& vec) {
const bool usingSpecial{vec.get_allocator().resource() == &k_SpecialMemoryResource};
std::cout << std::boolalpha << usingSpecial << std::endl;
return usingSpecial;
}
void Func(const std::pmr::vector<int>& vec) {
const bool LHS = true, RHS = false;
const std::pmr::vector<int>& localLValRef{std::pmr::vector<int>{&k_SpecialMemoryResource}};
isUsingSpecialMemoryResource(LHS? vec : localLValRef);
isUsingSpecialMemoryResource(RHS? vec : localLValRef);
isUsingSpecialMemoryResource(LHS? vec : std::pmr::vector<int>{&k_SpecialMemoryResource});
isUsingSpecialMemoryResource(RHS? vec : std::pmr::vector<int>{&k_SpecialMemoryResource});
}
int main() {
const auto specialVec = std::pmr::vector<int>{&k_SpecialMemoryResource};
Func(specialVec);
}
运行上面的代码将导致:
true true false true
为什么在第三种情况下不传播polymorphic_allocator的memory_resource?我在这里的期望是,我只是绑定引用,而不构造/转换任何对象std::pmr::vector
,因此我认为任何原因都不会改变。但是,我是否在条件运算符的类型推导中缺少某些内容,这些内容触发了不传播分配器的std::pmr::vector
副本构造?
- 复制构造函数。用other的内容的副本构造容器,就像通过调用获得分配器一样
std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.get_allocator()).
或者是其他东西?我不确定发生了什么,并且发现条件运算符的类型推导文档难以解析。
我正在使用clang10进行编译-std=c++20
:
clang version 10.0.0-4ubuntu1 Target: x86_64-pc-linux-gnu Thread model: posix
true ? vec : std::pmr::vector<int>{&k_SpecialMemoryResource}
确实创建了一个临时对象,该对象是从复制初始化的vec
:
[expr.cond] / 2如果第二个或第三个操作数的类型为
void
... [不适用]
3否则,如果第二个和第三个操作数为glvalue位字段... [不适用]
4否则,如果第二和第三操作数具有不同的类型...或两者都是glvalues ... [不适用]
5如果第二和第三操作数是glvalues ... [不适用][expr.cond] / 6否则,结果为prvalue ...
[expr.cond] / 7 Lvalue -to-rvalue ...对第二个和第三个操作数执行标准转换。进行这些转换之后,应满足下列条件之一:
(7.1)—第二和第三操作数具有相同的类型;结果是该类型的结果,并且使用所选操作数初始化结果对象。
因此,对进行左值到右值转换vec
:
[conv.lval] / 3转换的结果是根据以下规则确定的:
(3.2)—否则,如果T
具有类类型,则转换会从glvalue复制初始化结果对象。
现在,我们必须查看的副本构造函数的行为std::pmr::vector<T>
,它是的别名std::vector<T, std::pmr::polymorphic_allocator<T>>
。事实证明,副本获得了一个默认构造的分配器。内存资源不传播。您观察到的是什么。
[container.requirements.general] / 8除非另有说明,否则本节中定义的所有容器都使用分配器获取内存...这些容器类型的复制构造函数通过调用
allocator_traits<allocator_type>::select_on_container_copy_construction
属于要复制的容器的分配器来获取分配器。
[allocator.traits.members] / 8
static Alloc select_on_container_copy_construction(const Alloc& rhs);
返回:rhs.select_on_container_copy_construction()
如果该表达式格式正确;则返回0。否则,rhs
。
[mem.poly.allocator.mem] / 15
polymorphic_allocator select_on_container_copy_construction() const;
返回:polymorphic_allocator()
。
16 [注意:不传播内存资源。—尾注]
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句