`std::pmr::monotonic_buffer_resource`:为什么需要使用 `dynamic_cast`?

4
草案标准N4618关于std::pmr::monotonic_buffer_resource的说明如下:
bool do_is_equal(const memory_resource& other) const noexcept override;

Returns: this == dynamic_cast<const monotonic_buffer_resource*>(&other)

换句话说,标准要求供应商不仅要使用this == &rhs比较指针是否相等,而且要特意进行dynamic_cast的右侧指针。
我想不出任何情况下dynamic_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);

这种差异是否存在微妙的原因?如果标准通过删除dynamic_cast,使operator==具有自反性/对称性/传递性,会出现什么问题?


2
this == &other 没有意义,因为这两个操作数具有不同的类型! - Kerrek SB
2
@kerreksb 嗯?&other是静态类型为memory_resource*,而this的静态类型是monotonic_buffer_resource*,它可以隐式转换为memory_resource*。这是经典的面向对象继承,不是吗? - Quuxplusone
@ÖöTiib:do_is_equal是由基类std::pmr::memory_resource提供的私有虚方法。有关详细信息,请参见cppreference,我认为这些内容超出了此特定问题的范围。 - Quuxplusone
1
熟悉 pmr 设计并能回答这些问题的人数可以用一只手或两只手来计算。而在 Stack Overflow 经常出没的这样的人数大约为零。 - T.C.
1
@T.C.:好的,我已经做到了。不过他直到九月份才回来,所以我不指望很快能得到权威的回复。但是,世界上肯定有其他人理解这个标准草案的这一部分吧?毕竟很多人都投票通过了,肯定至少有几个人先读了它。:P - Quuxplusone
显示剩余6条评论
1个回答

7

这是一个已知的缺陷,尽管您的问题提醒我需要提交一个正式的问题报告。

this == &other 的简单表达是它应该的样子。 dynamic_cast 是一种保留代码,其中等式的 rhs 不必是 lhs 相同的对象才能被视为相等。在最一般的情况下,如果两个 pmr::memory_resource 对象是可互换的但没有相同的地址,则必须将 rhs 动态转换为 lhs 的类型以确定相等性。但是,在 pmr::monotonic_buffer_resource 的情况下,需要地址相等,因此 dynamic_cast 是多余的。

你的 TwoHeadedResource 很聪明。向你致敬,因为你找到了一种会产生影响的情况,即使那不是我们所支持的代码类型 :-)。

编辑:现在在 http://cplusplus.github.io/LWG/lwg-active.html#3000 上有一个官方的问题报告。


谢谢Pablo!在过去的几个月中,我已经决定 dynamic_cast 是一种代码味道,因为需要它的代码非常罕见,并且使用它的代码正确性极低。来参加我的CppCon 2017演讲“从零开始学习dynamic_cast”,听我抱怨它(但主要是关于没有供应商正确地实现它,尽管需要它的代码非常罕见,这不重要)。 - Quuxplusone
谢谢,@Quuxplusone。我会找那个讲座的。你也可以找我的演讲:《分配器 - 好的部分》在这个CppCon上。希望我们不会在同一时间段。 - Pablo Halpern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接