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::string
s 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?
The first would be to implement a class around a
char
array and then implement more or less all the functions that thestd::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 thebasic_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.