Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How string accepting interface should look like?

Tags:

c++

This is a follow up of this question. Suppose I write a C++ interface that accepts or returns a const string. I can use a const char* zero-terminated string:

void f(const char* str); // (1)

The other way would be to use an std::string:

void f(const string& str); // (2)

It's also possible to write an overload and accept both:

void f(const char* str); // (3)
void f(const string& str);

Or even a template in conjunction with boost string algorithms:

template<class Range> void f(const Range& str); // (4)

My thoughts are:

  • (1) is not C++ish and may be less efficient when subsequent operations may need to know the string length.
  • (2) is bad because now f("long very long C string"); invokes a construction of std::string which involves a heap allocation. If f uses that string just to pass it to some low-level interface that expects a C-string (like fopen) then it is just a waste of resources.
  • (3) causes code duplication. Although one f can call the other depending on what is the most efficient implementation. However we can't overload based on return type, like in case of std::exception::what() that returns a const char*.
  • (4) doesn't work with separate compilation and may cause even larger code bloat.
  • Choosing between (1) and (2) based on what's needed by the implementation is, well, leaking an implementation detail to the interface.

The question is: what is the preffered way? Is there any single guideline I can follow? What's your experience?

Edit: There is also a fifth option:

void f(boost::iterator_range<const char*> str); // (5)

which has the pros of (1) (doesn't need to construct a string object) and (2) (the size of the string is explicitly passed to the function).

like image 482
Yakov Galka Avatar asked Dec 06 '22 00:12

Yakov Galka


1 Answers

If you are dealing with a pure C++ code base, then I would go with #2, and not worry about callers of the function that don't use it with a std::string until a problem arises. As always, don't worry too much about optimization unless there is a problem. Make your code clean, easy to read, and easy to extend.

like image 54
Mark Loeser Avatar answered Dec 09 '22 14:12

Mark Loeser