c++stringtemplatesstdstringpolicy-based-design

C++ Policy Based Design


What I do not understand in the Alexandrescu policy based design is the creation of new types without anything in common where, in my opinion, there is still a lot in common that should be represented somehow.

For example, std::string and std::basic_string<>: allocator are something very internal and, in my opinion, the code using that class shall not be aware of which allocator that class is using.

BUT since a new type has been created, let's say std::basic_string_1, all those methods which are passing around an std::string& are basically broken, and I can't see a valid reason why an std::basic_string<> with a different allocator shall be considered totally different from an std::basic_string<> with another allocator.

My question is: why there is not common parent for every std::basic_string<>, so that this problem could be avoided? Generally in my code when I have a Whatever<T>, I make it inherits from a WhateverBase of some sort, and when T is not shown on the public interface of that class, it works greatfully...


Solution

  • allocator are something very internal and, in my opinion, the code using that class shall not be aware of which allocator that class is using.

    Which is why usually you don't care, and just use std::string. Most code doesn't use custom allocators, so it simply isn't a problem.

    As Kerrek SB points out in a comment, you have the option of using std::experimental::pmr::string which uses a type-erased allocator, so the details of exactly what kind of allocator is used are hidden. That has some run-time cost, but also has some advantages.

    More generally, you're right that policy-based designs lead to an explosion of different types that don't interoperate. Sometimes that is a problem (and sometimes it isn't). One approach to dealing with that is to write generic code that doesn't care if it deals with policy_base_ptr<X, Y, Z> or policy_based_ptr<A, B, C>. Write generic code that uses "some kind of smart pointer" and you don't care about the exact type. That isn't always an option though, for example when defining an interface, where you often need to use concrete types.

    My question is: why there is not common parent for every std::basic_string<>, so that this problem could be avoided? Generally in my code when I have a Whatever<T>, I make it inherits from a WhateverBase of some sort, and when T is not shown on the public interface of that class, it works greatfully...

    That means your class is polymorphic, and code that only knows about the base class must pass it by reference. It cannot be passed by value because it will be sliced. That means you have to be careful about object ownership, and care about when the reference is still valid, and who is responsible for destroying the derived type.

    That is a perfectly reasonable choice for you to make in your own software, but is not suitable for a general purpose vocabulary type like std::string. It is essential that strings can be passed around by value and copied easily.