C++ `std::pmr::单调的缓冲区资源`:为什么使用“动态”强制转换`?
标准草案N4618对C++ `std::pmr::单调的缓冲区资源`:为什么使用“动态”强制转换`?,c++,c++17,dynamic-cast,allocator,C++,C++17,Dynamic Cast,Allocator,标准草案N4618对std::pmr::monotonic\u buffer\u resource作了这样的规定: 返回:this==dynamic\u cast(&other) 换句话说,该标准不只是将指针与this==&rhs进行相等性比较,而是希望供应商特意使用dynamic\u cast右侧指针 我想不出任何一种理智的情况下,dynamic\u cast会改变比较的结果。但我能想到一些疯狂的案例: class new_delete_memory_resource : public mem
std::pmr::monotonic\u buffer\u resource
作了这样的规定:
返回:this==dynamic\u cast(&other)
换句话说,该标准不只是将指针与this==&rhs
进行相等性比较,而是希望供应商特意使用dynamic\u cast
右侧指针
我想不出任何一种理智的情况下,dynamic\u cast
会改变比较的结果。但我能想到一些疯狂的案例:
class new_delete_memory_resource : public memory_resource {
void *do_allocate(size_t bytes, size_t align) override {
return ::operator new(bytes, align);
}
void *do_deallocate(void *p, size_t bytes, size_t align) override {
::operator delete(p, bytes, align);
}
bool do_is_equal(const memory_resource& rhs) const noexcept override {
return (this == &rhs);
}
};
class TwoHeadedResource :
public new_delete_memory_resource,
public monotonic_buffer_resource
{
};
TwoHeadedResource thr;
memory_resource *a = static_cast<new_delete_memory_resource *>(thr);
memory_resource *b = static_cast<monotonic_buffer_resource *>(thr);
assert(*a != *b);
assert(*b == *a);
class新建\删除\内存\资源:公共内存\资源{
void*不分配(大小字节、大小对齐)覆盖{
return::运算符new(字节,对齐);
}
void*do\u解除分配(void*p,大小字节,大小对齐)覆盖{
::运算符删除(p,字节,对齐);
}
bool do_等于(常量内存资源和rhs)常量noexcept覆盖{
返回(this==&rhs);
}
};
二类人头资源:
公共新建删除内存资源,
公共单调缓冲区资源
{
};
双头资源;
内存资源*a=静态广播(thr);
内存资源*b=静态广播(thr);
断言(*a!=*b);
断言(*b==*a);
这种差异有微妙的原因吗?如果标准通过删除
动态转换,使运算符==
自反/对称/传递,会出现什么问题?这是一个已知的缺陷,尽管您的问题提醒我需要提交正式的问题报告
this==&other
的简单公式应该是这样的。dynamic_cast
是一些样板代码的保留,根据这些样板代码,相等的rhs不必与lhs是同一个对象才能被视为相等。在最常见的情况下,如果两个pmr::memory\u resource
对象可以互换,但地址不同,则必须将rhs动态转换为lhs的类型,以确定相等性。但是,在pmr::monotonic\u buffer\u resource
的情况下,需要地址相等,因此动态\u cast
是多余的
不过,您的TwoHeadedResource
很聪明。向您致敬,因为您发现了一种情况,在这种情况下,它将产生影响,尽管这不是我们想要支持的代码类型。:-)
编辑:现在有关于此缺陷的正式问题报告。此==&other
没有意义,因为两个操作数的类型不同@kerreksb呃和other
是静态类型的内存\u资源*
,而这个是静态类型的单调缓冲\u资源*
,它可以隐式转换为内存\u资源*
。这是经典的OO继承,不是吗?如果要比较内存和资源对象地址,那么do_是虚拟的,这有什么意义呢?对pmr的设计足够熟悉以回答这些问题的人的数量可以从一两方面计算出来。这样的人也经常这样做的人数大约为零。@T.C:好的,我已经这样做了。不过,事实证明,他在9月份之前一直处于昏迷状态,所以我预计不会很快得到权威回应。当然,世界上至少还有一个人理解标准草案的这一部分?我是说一群人投了票;当然,至少有几个人是先读的帕布罗!在过去的几个月里,我决定dynamic\u cast
是一种代码气味,因为需要它的代码非常罕见,使用它的代码正确使用它的几率非常低。来参加我的2017年CppCon演讲“dynamic_cast
from scratch”,听听我如何发泄(但主要是如何发泄,这并不重要,因为需要它的代码非常罕见)。谢谢,@Quuxplusone。我会找那个谈话的。你也可以在这个CppCon上找到我的演讲:分配器——好的部分。幸运的话,他们不会在同一个时间段。
class new_delete_memory_resource : public memory_resource {
void *do_allocate(size_t bytes, size_t align) override {
return ::operator new(bytes, align);
}
void *do_deallocate(void *p, size_t bytes, size_t align) override {
::operator delete(p, bytes, align);
}
bool do_is_equal(const memory_resource& rhs) const noexcept override {
return (this == &rhs);
}
};
class TwoHeadedResource :
public new_delete_memory_resource,
public monotonic_buffer_resource
{
};
TwoHeadedResource thr;
memory_resource *a = static_cast<new_delete_memory_resource *>(thr);
memory_resource *b = static_cast<monotonic_buffer_resource *>(thr);
assert(*a != *b);
assert(*b == *a);