c++ - 类型删除和分配器 : what's the expected behavior?

标签 c++ templates type-erasure allocator

我在 codereview 上也问过同样的问题,但他们善意地指出,这个问题更适合 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);
}

这是一个用于解决问题的最小示例。
这个想法是类型删除接受自定义分配器(在本例中为std::vector)的东西,以便改变容器的定义(即将分配器的类型作为其类型的一部分)类似于 std::function 的类型(不将分配器的类型作为其类型的一部分,但仍然接受分配器施工期间)。

上面的代码可以编译,但我对这个类是否能按预期工作这一事实表示怀疑。
换句话说,每当该类的用户提供自己的分配器时,它都会用作新的 std::vector 的参数,其类型会被删除,但不会用于分配ptr 指向的 D 实例。

这是一个有效/合乎逻辑的设计吗?或者分配器应该对每次分配保持一致? 我的意思是,这是否也可以在 STL 或其他一些主要库中找到,或者它没有多大意义?

最佳答案

没有正确的答案,设计是合理的,但使用用户提供的分配器来创建派生对象也是合理的。为此,您需要在类型删除的上下文中进行销毁和释放,以便可以使用分配器:

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::pointerAllocator::value_type*,为了支持分配器,如果情况不正确,则需要使用 pointer_traits 在指针类型之间进行转换,这留给读者作为练习。)

关于c++ - 类型删除和分配器 : what's the expected behavior?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36028562/

相关文章:

java - JpaRepository 的泛型没有类型删除?

android - Qt for Android - 未定义对 ANativeWindow_fromSurface 的引用

c++ - 使用 FileSource 加密内容后无法删除文件

c++ - 异步套接字输入输出

c++ - 隐式与显式接口(interface)

c++ - C++0x 中的 disable_if 在哪里?

scala - Scala 的类型删除如何用于更高种类的类型参数?

c++ - 在 C++ 中删除带有 vector<const char *> 的类

c++ - 是否可以在不指定类型的情况下从 istringstream 转到 vector ?

c++ - 为什么 unique_ptr 将删除器作为类型参数而 shared_ptr 没有?