`std::pmr::monotonic_buffer_resource`:为什么是 `dynamic_cast`?

`std::pmr::monotonic_buffer_resource`: why the `dynamic_cast`?

标准草案 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== reflexive/symmetric/transitive 出现什么问题?

这是一个已知缺陷,不过你的问题确实提醒我需要提交正式的问题报告。

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.

上有针对此缺陷的官方问题报告