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.
std::string_view
in C++17, you could rig up something very simple combining an array of chars and a string view... – Plasmagelstd::string
and just not allow operations that would let it grow? – Uptotheminutetemplate <int T> class fstring : std::string
... figure out the rest ? – Epidotetemplate <int T> class fstring : std::string
... figure out the rest" I came this far. So you would go with writing a wrapper, hiding all the functions that would change the size? – Telegraphicstd::array<char, some_number>
with just a couple of functions that could probably be implemented using STL algorithms. – Blipstd::basic_string<CharT, std::char_traits<CharT>, MyFixedSizeAllocator<CharT>>
? – Checkrowstd::string
seems to not adjust allocation size according toallocator::max_size
:-/ – Checkrowstd::string
(orconst&
of it)? 3. Do you need full defense (e.g. library code) or just a quick check that you don't call anything wrong? 4. – Nancestd::string
? (If no, you can make a macro that defines a delegator fn using perfect fwding.) 6. Do you want the string on heap/stack? – Nance