Comparing 3 modern c++ ways to convert integral values to strings
Question 1. Why is the string stream method consistently the worst?
The classical mistake: creating a new stringstream every single time
template<typename T> // 1. Using stringstream
string StringFromIntegral_SS(T const &value) {
thread_local stringstream ss;
ss.str("");
ss.clear();
ss << value;
return ss.str();
}
Question 2. Why is lexical cast consistently the best? Can we assume that this is the fastest implementation ?
Because it's most specialized; and, no, faster implementations exist. FastFormat and Boost Spirit have competitive offerings, as far as I know.
Update Boost Spirit Karma still easily beats the bunch:
template<typename T> // 4. Karma to string
std::string StringFromIntegral_K(T const &value) {
thread_local auto const gen = boost::spirit::traits::create_generator<T>::call();
thread_local char buf[20];
char* it = buf;
boost::spirit::karma::generate(it, gen, value);
return std::string(buf, it);
}
Timings:
C++ 11 method 111
String stream method 103
Lexical cast method 57
Spirit Karma method 36
Spirit Karma method with string_ref 13
See it Live On Coliru Clang or GCC
BONUS
Just to goof off, a version using boost::string_ref
is much faster still due the reduced allocations:
template<typename T> // 5. Karma to string_ref
boost::string_ref StringFromIntegral_KSR(T const &value) {
thread_local auto const gen = boost::spirit::traits::create_generator<T>::call();
thread_local char buf[20];
char* it = buf;
boost::spirit::karma::generate(it, gen, value);
return boost::string_ref(buf, it-buf);
}
I've tested all modified methods for correctness using an asserting test loop:
return measure<>::execution(
//[&]() { for (auto const &i : v1) { func(i); }});
[&]() { for (auto const &i : v1) { assert(func(i) == StringFromIntegral_LC(i)); }});
Easiest way to convert int to string in C++
C++11 introduces std::stoi
(and variants for each numeric type) and std::to_string
, the counterparts of the C atoi
and itoa
but expressed in term of std::string
.
#include <string>
std::string s = std::to_string(42);
is therefore the shortest way I can think of. You can even omit naming the type, using the auto
keyword:
auto s = std::to_string(42);
Note: see [string.conversions] (21.5 in n3242)
Compare two string as numeric value
Compare them digit by digit:
a = "3254353245423345432423133423421"
b = "3254353245423345432443133423421"
for(int i = 0; i < a.length(); ++i):
if ((a[i] - '0') < (b[i] - '0'))
{
std::cout << "b is larger!"
}
I'm sure you can take it from here if you want to find out whether b
is larger than a
, or if they are equal. Alternatively, if they are different lengths, the larger one wins! (Check for zeros at the beginning, i.e. "000443342"
) Don't forget to consider negative numbers.
C++: string.find finds a char in a string only if its on pos1
The return type of std::string::find()
is the unsigned type std::string::size_type
, and it returns either std::string::npos
(which is the maximum value that std::string::size_type
can represent) if the character was not found, or the first index of the found character in the string.
Now you are comparing the result of std::string::find()
to the true
, which results in integral promotion of the Boolean value true
to the integral value 1
. Thus, your condition is satisfied if and only if the character expected_char
is found in position 1 (i.e. when it is the second character in the string).
If you want to check whether the character expected_char
is in the string word
, use
if (word.find(expected_char) != std::string::npos)
{
...
}
Verbatim stringify
Yes, add the manipulator(s) you desire to the function signature and forward them to the stream.
template<typename T, typename Manip>
std::string Stringify(T const &value, Manip manip)
{
std::stringstream ss;
ss << manip << value;
return ss.str();
}
With the sample code;
int main()
{
using namespace std;
// The precision here is set to be sufficient to print the test platform
cout << Stringify(numeric_limits<float>::max(), setprecision(50)) << endl;
}
I assume that more than one manipulator will be used. To this end, function overloads can be added for the desired number of manipulators, or you can use (with C++11) variadic templates and perfect forwarding.
template <typename Stream>
Stream& AddManip(Stream& str)
{
// end the recursion
return str;
}
template <typename Stream, typename Head, typename... Tails>
Stream& AddManip(Stream& str, Head&& head, Tails&&... tails)
{
// add the head manipulator and forward the rest
str << std::forward<Head>(head);
return AddManip(str, std::forward<Tails>(tails)...);
}
template<typename T, typename... Manip>
std::string Stringify(T const &value, Manip&&... manip)
{
std::stringstream ss;
// add the manipulators to the stream
AddManip(ss, std::forward<Manip>(manip)...);
ss << value;
return ss.str();
}
int main()
{
using namespace std;
cout << Stringify(numeric_limits<int>::max(), setprecision(40), std::hex) << endl;
}
Is boost::lexical_cast redundant with c++11 stoi, stof and family?
boost::lexical_cast
- handles more kinds of conversion, including iterator pairs, arrays, C strings, etc.
- offers the same generic interface (
sto*
have different names for different types) - is locale-sensitive (
sto*
/to_string
are only in part, e.g.lexical_cast
can process thousands separators, whilestoul
usually doesn't)
Integer to string optimized function?
You may want to read this article by Alexei Alexandrescu, where he talks about low-level optimizations by using a (fixed-radix) int to string conversion as an example:
https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
Keep in mind that the most important thing when optimizing is always profiling.
How can I convert a std::string to int?
In C++11 there are some nice new convert functions from std::string
to a number type.
So instead of
atoi( str.c_str() )
you can use
std::stoi( str )
where str
is your number as std::string
.
There are version for all flavours of numbers:long stol(string)
, float stof(string)
, double stod(string)
,...
see http://en.cppreference.com/w/cpp/string/basic_string/stol
Related Topics
Why Must Std::Sort Compare Function Return False When Arguments Are Equal
What Is the Safe Way to Fill Multidimensional Array Using Std::Fill
Which Is Faster: X<<1 or X<<10
Shared_Ptr<> Is to Weak_Ptr<> as Unique_Ptr<> Is To... What
Can the 'Type' of a Lambda Expression Be Expressed
Are There Any Downsides to Using Upx to Compress a Windows Executable
Simpler Way to Create a C++ Memorystream from (Char*, Size_T), Without Copying the Data
C++ Memory Barriers for Atomics
Erase/Remove Contents from the Map (Or Any Other Stl Container) While Iterating It
How to Extend a Lexical Cast to Support Enumerated Types
Passing a Pointer to a Class Member Function as a Parameter
Openmp: What Is the Benefit of Nesting Parallelizations
Easiest Way to Make a Cyclic Iterator (Circulator)
Std::Back_Inserter for a Std::Set
Initializing Container of Unique_Ptrs from Initializer List Fails with Gcc 4.7