Why are C++11 string new functions (stod, stof) not member functions of the string class?
Asked Answered
A

3

7

Why are those C++11 new functions of header <string> (stod, stof, stoull) not member functions of the string class ?

Isn't more C++ compliant to write mystring.stod(...) rather than stod(mystring,...)?

Automata answered 29/1, 2014 at 9:28 Comment(4)
They don't need to be, and std::string already has far too many member functions. See the Monoliths "unstrung" GOTW.Ankylostomiasis
It would have been nice if stod was a template that could take any Sequence object instead of just std::stringVistula
std::string is already a monolith of a class, it doesn't need more member functions.Wornout
There was a standards committee deciding this, so asking for "more C++ compliant" should ring a warning bell that the viewpoint here might be not the bestPolyphone
K
23

It is a surprise to many, but C++ is not an Object-Oriented language (unlike Java or C#).

C++ is a multi-paradigm language, and therefore tries to use the best tool for the job whenever possible. In this instance, a free-function is the right tool.

Guideline: Prefer non-member non-friend functions to member functions (from Efficient C++, Item 23)

Reason: a member function or friend function has access to the class internals whereas a non-member non-friend function does not; therefore using a non-member non-friend function increases encapsulation.

Exception: when a member function or friend function provides a significant advantage (such as performance), then it is worth considering despite the extra coupling. For example even though std::find works really well, associative containers such as std::set provide a member-function std::set::find which works in O(log N) instead of O(N).

Karykaryl answered 29/1, 2014 at 9:37 Comment(6)
If that guideline would just have been applied a little sooner to std::basic_string...Footsore
@pmr: Yes, std::basic_string and all the IO Streams are dinosaurs that pre-existed standardization; actually, the original version of string was entirely defined in terms of indices, and during the standardization process all the iterator overloads were added to make a sequence of it... but the former methods were kept for compatibility.Karykaryl
What if the workings of the global non-member non-friend functions rely on private data members of the class?Indefeasible
@0x499602D2: This is not possible by construction, since the very principle of a non-member non-friend function is to only have access to the public interface.Karykaryl
@MatthieuM. So this is implying that we should implement getters and setters?Indefeasible
@0x499602D2: I am afraid I am not, at all, following your line of reasoning. I never said anything about getters and setters... If you want to implement a method that absolutely requires access to the class internals then obviously it will be implemented as either a member function OR a friend function; there is no debate here. The guideline applies when you have the choice, and more often than not you do have the choice, you just need to step back to realize it. When you don't, you don't.Karykaryl
M
3

The fundamental reason is that they don't belong there. They don't really have anything to do with strings. Stop and think about it. User defined types should follow the same rules as built-in types, so every time you defined a new user type, you'd have to add a function to std::string. This would actually be possible in C++: if std::string had a member function template to, without a generic implementation, you could add a specialization for each type, and call str.to<double>() or str.to<MyType>(). But is this really what you want. It doesn't seem like a clean solution to me, having everyone writing a new class having to add a specialization to std::string. Putting these sort of things in the string class bastardizes it, and is really the opposite of what OO tries to achieve.

If you were to insist on pure OO, they would have to be members of double, int, etc. (A constructor, really. This is what Python does, for example.) C++ doesn't insist on pure OO, and doesn't allow basic types like double and int to have members or special constructors. So free functions are both an acceptable solution, and the only clean solution possible in the context of the language.

FWIW: conversions to/from textual representation is always a delicate problem: if I do it in the target type, then I've introduced a dependency on the various sources and sinks of text in the target type---and these can vary in time. If I do it in the source or sink type, I make them dependent on the the type being converted, which is even worse. The C++ solution is to define a protocol (in std::streambuf), where the user writes a new free function (operator<< and operator>>) to handle the conversions, and counts on operator overload resolution to find the correct function. The advantage of the free function solution is that the conversions are part of neither the data type (which thus doesn't have to know of sources and sinks) nor the source or sink type (which thus doesn't have to know about user defined data types). It seems like the best solution to me. And functions like stod are just convenience functions, which make one particularly frequent use easier to write.

Marilla answered 29/1, 2014 at 10:37 Comment(0)
T
1

Actually they are some utility functions and they don't need to be inside the main class. Similar utility functions such as atoi, atof are defined (but for char*) inside stdlib.h and they too are standalone functions.

Transoceanic answered 29/1, 2014 at 9:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.