Search code examples
c++sizefixedstdstringstring-length

Best Practice for Fixed Size String Class


I would like to have a fixed size string class. Ideally, the interface would match the one of std::string with the one difference that the new class never allocates new memory. It is supposed to be a handy class for application cases where allocating new memory should be avoided. The size can be static (known at compile time).

I think there are two ways. The first would be to implement a class around a char array and then implement more or less all the functions that the std::string has. I also would have to implement some operators to create std::strings with a given fixed size string, etc.

The second method, I'm not even sure is possible, would be to inherit from std::string and override all the functions that may change the size of the string. I looked into the basic_string header in Visual Studio and it doesn't seem to be virtual, so I guess this is not the way to go.

What would you say is the best approach for implementing such class?


Solution

  • The first would be to implement a class around a char array and then implement more or less all the functions that the std::string has.

    This is definitely the way to go. It's easy to write, easy to use, and difficult to misuse.

    template <size_t N>
    class fixed_string {
        char array[N+1];
        size_t size;
    
    public:
        fixed_string() : size(0) { array[0] = '\0'; }
    
        // all the special members can be defaulted
        fixed_string(fixed_string const&) = default;
        fixed_string(fixed_string&&) = default;
        fixed_string& operator=(fixed_string const&) = default;
        fixed_string& operator=(fixed_string&&) = default;
        ~fixed_string() = default;
    
        // ...
    };
    

    All the accessors (data, c_str, begin, end, at, operator[]) are one-liners. All the search algorithms are straightforward.

    The only real design question is what do you want the mutations to do on failure. That is:

    fixed_string<5> foo("abcde");
    foo += 'f'; // assert? throw? range-check internally and ignore?
                // just not even add this and instead write a 
                // try_append() that returns optional<fixed_string&>?
    

    There are advantages and disadvantages to design choice, but regardless of which one you pick, the implementation of each function is also going to be very concise.


    The second method, I'm not even sure is possible, would be to inherit from std::string and override all the functions that may change the size of the string. I looked into the basic_string header in Visual Studio and it doesn't seem to be virtual, so I guess this is not the way to go.

    Whether or not anything in std::string is virtual is irrelevant to the question of whether or not this is a good idea. You would definitely want to start from:

    template <size_t N>
    class fixed_string : private std::string { ... }
    //                  ^^^^^^^^^
    

    Since your type would definitely not fit the is-a relationship with std::string. It's not a std::string, it'd merely be implemented in terms of it. Private inheritance would make this code ill-formed:

    std::string* p = new fixed_string<5>();
    

    so you don't have to worry about lack of virtual.

    That said, inheriting from string is going to make for a much more complicated, less efficient implementation than just going the direct route, with way more potential pitfalls. It's probably possible to implement such a thing, but I can't see how it would be a good idea.