C++ 取常数pmr::vector<&燃气轮机&;使用带右值的条件运算符时不传播分配器
为什么在第三种情况下不传播?我在这里的期望是,我只是绑定引用,而不是构造/转换任何C++ 取常数pmr::vector<&燃气轮机&;使用带右值的条件运算符时不传播分配器,c++,c++17,C++,C++17,为什么在第三种情况下不传播?我在这里的期望是,我只是绑定引用,而不是构造/转换任何std::pmr::vector,因此我认为没有任何理由会改变。但是,我是否在的类型推断中遗漏了一些触发不传播分配器的std::pmr::vector 复制构造函数。使用 另一个的内容,分配器是通过调用 std::allocator\u traits::select\u on\u container\u copy\u构造(other.get\u allocator())。 还是别的什么?我不确定发生了什么,并且发现
std::pmr::vector
,因此我认为没有任何理由会改变。但是,我是否在的类型推断中遗漏了一些触发不传播分配器的std::pmr::vector
std::allocator\u traits::select\u on\u container\u copy\u构造(other.get\u allocator())。
-std=c++20
:
对吗?vec:std::pmr::vector{&k_SpecialMemoryResource}
确实创建了一个临时对象副本,该副本是从vec
初始化的:
[expr.cond]/2如果第二个或第三个操作数的类型为void
。。。[不适用]3否则,如果第二个和第三个操作数是glvalue位字段。。。[不适用]
4否则,如果第二个和第三个操作数的类型不同。。。或者如果两者都是GLV值。。。[不适用]
5如果第二个和第三个操作数是glvalues。。。[不适用] [expr.cond]/6否则,结果为prvalue…
[expr.cond]/7从左值到右值。。。执行标准转换 在第二个和第三个操作数上。在这些转换之后,以下其中一项应保持不变:
(7.1)-第二个和第三个操作数的类型相同;结果属于该类型,并且使用选定的操作数初始化结果对象 因此,在
vec
上执行左值到右值的转换:
[conv.lval]/3转换结果根据以下规则确定:(3.2)-否则,如果
T
具有类类型,则转换副本将从glvalue初始化结果对象
现在我们必须看看
std::pmr::vector
的复制构造函数的行为,它是std::vector
的别名。结果是,副本得到了一个默认构造的分配器;内存资源未被传播。这就是你观察到的
[container.requirements.general]/8除非另有规定,否则本条中定义的所有容器都使用分配器获取内存。。。这些容器类型的复制构造函数通过在属于被复制容器的分配器上调用allocator\u traits::select\u on\u container\u Copy\u construction
来获取分配器
[allocator.traits.members]/8静态Alloc-select\u-on\u-container\u-copy\u构造(const-Alloc&rhs)代码>
返回:rhs。如果表达式格式正确,请选择\u on\u container\u copy\u construction()
;否则,rhs
[mem.poly.allocator.mem]/15多态分配器选择容器上的复制构造()常量代码>
返回:多态分配器()
16[注意:内存资源未被传播。-结束注意]
LHS?vec:std::pmr::vector{&k_SpecialMemoryResource}
确实需要创建一个从vec
构造的临时副本。表达式必须是左值或右值,有时不能是左值,有时不能是右值,具体取决于操作数的运行时值。因此,?:
的规则是,如果其中一个分支是右值,则整个表达式是右值,并根据需要创建临时表达式。现在,为什么这个副本不传播资源,我不确定<代码>多态\u分配器::选择容器上的\u复制\u构造
以返回默认构造的多态\u分配器
,而不传播资源。
#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
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix