类型擦除和分配器:期望的行为是什么? [英] Type erasure and allocators: what's the expected behavior?

查看:224
本文介绍了类型擦除和分配器:期望的行为是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 codereview 上也提出过同样的问题,但他们非常注意这个问题更适合SO。

I asked the same on codereview, but they kindly noted that this question is better suited to SO.

请考虑以下代码:

#include<vector>
#include<memory>

template<typename T>
struct S final {
    struct B {
        virtual void push_back(T&& v) = 0;
        virtual ~B() { }
    };

    template<class Allocator>
    struct D final: public B {
        D(Allocator alloc): vec{alloc} { }
        void push_back(T&& v) override { vec.push_back(v); }
        std::vector<T, Allocator> vec;
    };

    S(): S{std::allocator<T>{}} { } 

    template<class Allocator>
    S(Allocator alloc): ptr{new D<Allocator>{alloc}} { }

    ~S() { delete ptr; }

    void push_back(T&& v) { ptr->push_back(std::move(v)); }

    B* ptr;
};

int main() {
    int x = 42;
    S<int> s1{};
    S<double> s2{std::allocator<double>{}}; 
    s1.push_back(42);
    s2.push_back(x);
}

这是问题目的的最小例子。

这个想法是接受自定义分配器的 type-erase 类型(在这种情况下, std :: vector ),将容器的定义(具有作为其类型的一部分的分配器的类型)转换为类似于 std :: function (不具有类型作为其类型的一部分,但在构造期间仍然接受分配器)。

It's a minimal example for the purpose of the question.
The idea is to type-erase something that accepts a custom allocator (in this case, a std::vector), so as to bend the definition of the container (that has the type of the allocator as part of its type) to something similar to the one of std::function (that has not the type of the allocator as part of its type, but still accepts an allocator during the construction).

上面的代码编译,但我怀疑这个类工作的事实

在其他方面,每当类的用户提供自己的分配器时,它被用作新的 std :: vector ,其类型被擦除,但不用于分配指向的 D 的实例

The code above compiles, but I have doubts about the fact that this class works as it is expected to do.
In other terms, whenever an user of the class provides its own allocator, it is used as an argument for the new std::vector, the type of which is erased, but it is not used to allocate the instance of D pointed to by ptr.

这是一个有效/逻辑设计,还是应该为每个分配一致地使用分配器?
我的意思是,是在STL还是其他主要库中可以找到的东西,或者它是没有什么意义的东西。

Is this a valid/logical design, or the allocator should be used consistently for each allocation? I mean, is that something that can be found also in the STL or some other major library, or it's something that doesn't make much sense?

推荐答案

没有正确的答案,设计是合理的,但使用用户提供的分配器创建派生对象也是合理的。要做到这一点,你需要在类型删除的上下文中执行销毁和释放,所以可以使用分配器:

There's no right answer, the design is reasonable, but it would also be reasonable to use the user-supplied allocator for the creation of the derived object. To do that you'd need to do the destruction and deallocation in the type-erased context, so the allocator can be used:

template<typename T>
struct S final {
    struct B {
        // ...
        virtual void destroy() = 0;
    protected:
        virtual ~B() { }
    };

    template<class Allocator>
    struct D final: public B {
        // ...
        void destroy() override {
            using A2 = std::allocator_traits<Allocator>::rebind_alloc<D>;
            A2 a{vec.get_allocator()};
            this->~D();
            a2.deallocate(this, 1);
        }
    };

    S(): S{std::allocator<T>{}} { } 

    template<class Allocator>
      S(Allocator alloc): ptr{nullptr} {
          using DA = D<Allocator>;
          using AT = std::allocator_traits<Allocator>;
          static_assert(std::is_same<typename AT::pointer, typename AT::value_type*>::value, "Allocator doesn't use fancy pointers");

          using A2 = AT::rebind_alloc<DA>;
          A2 a2{alloc};
          auto p = a2.allocate(1);
          try {
              ptr = ::new((void*)p) DA{alloc};
          } catch (...) {
              a2.deallocate(p);
              throw;
          }
      }

    ~S() { ptr->destroy(); }

    // ...
};

(此代码声明 Allocator :: pointer Allocator :: value_type * ,为了支持不正确的分配器,你需要使用 pointer_traits 指针类型,这留给读者一个练习。)

(This code asserts that Allocator::pointer is Allocator::value_type*, to support allocators where that's not true you would need to use pointer_traits to convert between pointer types, which is left as an exercise for the reader.)

这篇关于类型擦除和分配器:期望的行为是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆