This google-benchmark code checked on Quick Bench, shows that string::empty()
runs a lot faster than comparing with an empty-string literal. However, creating a name string of ""
actually makes the compiler optimize away the check:
bool compareWithNamedConst(const std::string& target) {
const std::string emptyString = "";
return emptyString == target;
}
bool compareWithLiteral(const std::string& target) {
return "" == target;
}
bool compareWithRvalue(const std::string& target) {
return std::string{""} == target;
}
bool checkForEmpty(const std::string& target) {
return target.empty();
}
The performance for each of the calls is shown here:
As you can see, comparing with ""
is very slow compared to all the other options. I wonder why it is the case? It must be somehow related to SSO not being applied on const char*
, as testing this:
bool compareWithLiteral(const std::string& target) {
return "test with a longer string not optimized" == target;
}
bool compareWithRvalue(const std::string& target) {
return std::string{"test with a longer string not optimized"} == target;
}
Results comparing with a literal actually being faster:
I find that checking for string emptiness, the easiest syntax to read is "" == myVariable
as it clearly indicates that myVariable
is a std::string
with no unneccesary clutter. Why can't we have it optimized as we have all the other cases?
For emptyness check, if you really like the literal syntax, you may help your compiler by using namespace std::string_literals;
, and replacing ""
with ""s
. In that case compareWithLiteral
, compareWithRvalue
and checkForEmpty
would be essentially the same, since the operator==
between const std::string&
usually checks the sizes before the content, and the size of ""s
is trivial.
bool compareWithLiteral(const std::string& target) {
using namespace std::string_literals;
return ""s == target;
}
For strings not falling into the SSO, you should try with std::string_view
and its operator""sv
, even if unfortunately is available only since C++17. Boost has boost::string_view
. No user string literal is provided for compile time creation (essential because the test string length would be hardcoded in the binary), but you can easily define one:
#include <boost/utility/string_view.hpp>
constexpr auto operator""_sv(const char* str, std::size_t len) noexcept {
return boost::basic_string_view<char>{str, len};
}
bool compareWithLiteral(const std::string& target) {
return "test with a longer string not optimized"_sv == target;
}
This version runs much faster than your compareWithLiteral
version, at least when target
size is different.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With