How can I replace an std::string member with a non-heap limited-size string?

221 Views Asked by At

I have a codebase with some ubiquitous data structure; and said structure has an std::string member. Now, for reasons, I want this codebase to work when std::string is unavailable, and in fact with no dynamic allocation of memory (at least not the usual way). I can also verify that that string member never has a string longer than M characters (and M is small).

Now, what should I replace std::string with, so that I don't have to do a lot of rewriting, on one hand; and that my constraints are satisfied on the other?

Note:

  • I can't move the computation of the string to compile-time.
  • It's ok if the solution only has a trivial constructor, a const char* constructor, or both.
  • Solutions involving the use of std::string_view may be relevant (but I'm not sure whether that would be useful).
2

There are 2 best solutions below

2
On

char[M + 1] would probably be a decent, simple option to investigate. The amount of rewriting may be more or less depending on how you have used the string member so far.

If the "std::stringiness" of the member is used a lot, then you could possibly reduce the amount of rewrite by implementing a custom class that offers similar interface as std::string, but internally uses char[M + 1]. boost::static_string mentioned by Drew Dormann is a template for such class.

P.S. If you can still use std::string and are only restricted from using dynamic memory, then you could potentially keep using std::string with a custom allocator instead, as mentioned by Galik.

0
On

A minimum-hassle potential solution could utilize the specifics of your case, sacrificing generality for simplicity:

You wrote the string you want to replace is actually a member of another struct. This already allows using an array member of the struct, as @eerorika suggests, without worrying about array decay. But - arrays don't the interface of an std::string.

You said you didn't see how an std::string_view would be useful - and that's because there's no storage to go with it.

Well, combine the two! ... no, don't write a new class with both storage and a string interface. Rather, add a char [M+1] field to your struct, with a new field name, and use the original field name for a string_view looking at the array (with the appropriate length of course)!

This complicates construction and assignment a bit - i.e. it's no longer trivial member-wise construction - but you will then be able to pass this object around and use the same field as before like an std::string.

  struct ubiquitous {
     // other members
     char[M+1] string_data;
     std::string_view original_field;

     // apply rule of 5: ctor, move ctor, assignment, move assignment
     // and a trivial dtor (at least for your two fields)
     // ... so, a "rule of 4" in this case
  };

If you don't have a string_view available, i.e. it's pre-C++17 code, then you can get Martin Moene's back-ported string_view (GitHub).