2

I am in the process of writing a bespoke container class, somewhat streamlined for a particular purpose at work, but potentially of much wider use. (That's why am doing this during weekends so it doesn't end up as company IP. ;-) )

Looking at pmr::polymorphic_allocator (and e.g. this question), I am wondering if I even should provide a way to use the container with a non-polymorphic allocator (i.e. an allocator provided as template parameter). It seems to me that, with the advent of pmr::polymorphic_allocator, the non-polymorphic versions of the standard containers are basically kept for compatibility (which, obviously, is not an issue for a new container class).

Am I missing some technical consequence of only providing the "new" (polymorphic) allocator scheme?

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 1
    What is a "bespoke container"? Also, why would polymorphic allocators mean that you shouldn't use non-polymorphic allocators? – Nicol Bolas May 05 '18 at 13:26
  • This borders on an opinion question, which are considered off-topic. You might want to revise to focus on asking about comparisons of technical and practical consequences of the two approaches. – aschepler May 05 '18 at 13:27
  • @NicolBolas: I intentionally left that out so the discussion would not be sidetracked by "oh but you could instead...". It's a kind of std::string class, but more than that. – DevSolar May 05 '18 at 13:33
  • @aschepler: I thought that was the question I was asking -- if there is some consequence I have missed... edited the last line. – DevSolar May 05 '18 at 13:34
  • The _technical consequence_ is that users of your container incur a slight runtime cost in cases where the calls to the polymorphic allocator cannot be devirtualized. Here's a comparison of the code generated using a `pmr` container compared to a non-polymorphic one: https://godbolt.org/g/BSbfaC If you know how the container is going to be used and that this slight hit to performance is OK, then it could be worth it to support only `polymorphic_allocator` if it simplifies the code. – Sean Cline May 05 '18 at 14:31
  • @SeanCline: Is there a way to say in one or two line what those cases would be, and is there a way to minimize those? – DevSolar May 05 '18 at 14:53
  • 1
    I'm no expert here, so hopefully someone more knowledgeable can chime in. For devirtualization to happen, the compiler (or linker if `-flto` or `/LTCG`) needs know which function is going to be called. (i.e. it can deduce what a vtable or function pointer references) Unfortunately, the call to [`get_default_resource()`](http://en.cppreference.com/w/cpp/memory/get_default_resource) makes it hard for the compiler to be sure, since any part of the program could change the global default allocator using `set_default_resource()`. – Sean Cline May 05 '18 at 17:42
  • Even when removing the call to `get_default_resource()`, by manually specifying [`pmr::new_delete_resource`](http://en.cppreference.com/w/cpp/memory/new_delete_resource), I couldn't get `pmr::vector` to be completely devirtualized/inlined. See: https://godbolt.org/g/EFEkVB Still, this might be perfectly fine if a virtual function call isn't too much overhead for your use case. And if it does end up being a performance issue, you can always optimize later. – Sean Cline May 05 '18 at 17:46
  • `polymorphic_allocator` is a non-propagating stateful scoped allocator, so the behavior of containers using it can be confounding to people not used to such things. This may or may not be a problem. – T.C. May 05 '18 at 23:25

0 Answers0