4

I am trying to replace a class method which returns const std::string & with const boost::interprocess::basic_string &. The main challenge I am facing is the incompatibility between the two classes despite their implementation similarity. For more clear explanation I will put that into code

class A
{ std::string m_str;
 const std::string & StrVal() { return m_str; }
}

Now this class has to look like this:

typedef boost::interprocess::allocator<char,boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocatorChar;
typedef boost::interprocess::basic_string<char, std::char_traits<char>,ShmemAllocatorChar> ShMemString;

class A
{
 ShMemString m_str;
 const ShMemString & StrVal() { return m_str; }
}

The problem is that we have a huge code base depending on this:

A a;
const std::string & str = a.StrVal();
// Many string specific operations go here, comparing str with other std::strings for instance

Even If I go over all the code replacing the expected results with const ShMemString &, it will be an even harder work to also fix the uses that follow. I was surprised to find out that the boost's string does not include any comparison/construction methods from std::string.

Any ideas on how to approach this?

Yordan Pavlov
  • 1,303
  • 2
  • 13
  • 26

2 Answers2

2

Even if boost::interprocess::basic_string<> did have a conversion to std::basic_string<>, it would be completely useless for your purposes -- after the conversion, the interprocess string would be destroyed, and its allocator is the important one (i.e., the one holding the data in shared memory, which I assume is your motivation for switching basic_string<> implementations in the first place).

So, in the end, you have no choice but to go over all the code replacing the expected results with ShMemString const& (or auto const& if your compiler is recent enough to support it).


To make this less painful in the future, typedef judiciously:

struct A
{
    typedef ShMemString StrValType;
    StrValType const& StrVal() { return m_str; }
private:
    StrValType m_str;
};

// ...

A a;
A::StrValType const& str = a.StrVal();

This way, only the typedef inside of A needs to change and all code relying on it will automatically use the correct type.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • So, how does this solve the problem of the missing comparison functions from `interprocess::string`? – Nicol Bolas Sep 16 '11 at 20:59
  • @Nicol : Why should `boost::interprocess::string` have functions built-in to compare to `std::string`? What purpose would that serve other than to tightly couple the former to the latter? I.e., one can simply use any iterator-based algorithm and avoid the coupling. – ildjarn Sep 16 '11 at 21:05
  • 1
    That `interporcess::basic_string` shouldn't have comparison functions to `std::string` may be true. But saying it does not solve his problem. He still _needs_ those comparison functions in order to get done the things he needs to do. Your suggestion is basically to abandon `std::string` _everywhere_ in his codebase, even in places that aren't dealing with interprocess communication. That is an exceedingly heavyweight change, and there is no real need for it. – Nicol Bolas Sep 16 '11 at 21:19
  • @Nicol : No, I'm advocating using iterator-based comparison algorithms instead of `boost::interprocess::string`/`std::string` member functions. – ildjarn Sep 16 '11 at 22:12
2

The problem is that we have a huge code base depending on this:

Why does A::StrVal in the second one return an interprocess::basic_string? It is an implementation detail of the class A that it uses interprocess::basic_string internally. The actual string class it's interface uses does not have to be the same. This is simply poor refactoring.

A::StrVal should return a std::string, just like always (well, not a const& of course, but user code won't need to change because of that). And therefore, A::StrVal will need to do the conversion between the two string types. That's how proper refactoring is done: you change the implementation, but the interface stays the same.

Yes, this means you're going to have to copy the string data. Live with it.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I don't think it's an implementation detail that the class intends to return data stored in shared memory... – ildjarn Sep 16 '11 at 21:07
  • @ildjarn: It is if the last version of the class returned a `std::string`. And if the interface needs to change, then it should still support the old `std::string` interface while supporting the new one too. You _never_ modify an existing interface when you refactor something. You can add new interfaces, but you still need to support the old ones. – Nicol Bolas Sep 16 '11 at 21:17
  • I don't know what to say other than that I disagree almost completely. – ildjarn Sep 16 '11 at 22:13
  • @Nicol unfortunately keeping the interface and returning `std::string &` would involve keeping an additional member and synchronizing its value solely for the purpose of this method. – Yordan Pavlov Sep 17 '11 at 09:35
  • @Yordan: Who says that you would need to return a `std::string&`? Just return it by value. You return a `const std::string &` now, so even if they capture it by `const std::string &`, it will still work. The const& will extend the lifetime of the temporary. – Nicol Bolas Sep 17 '11 at 09:41
  • @Nicol: I see your idea now, 10x I would consider this. – Yordan Pavlov Sep 17 '11 at 09:54