Say you have a std::string and a boost::container::string just like this :
std::string stdString = "This is a test";
boost::container::string boostString = "This is a test";
Say you want to compare their content ; the following is not possible because we cannot compare their types :
stdString == boostString // no operator "==" matches these operands
You then choose to use both of their methods .c_str() to get a char* from each string. Not being sure if this does effectivly compare the strings, you try it :
stdString.c_str() == boostString.c_str() // compiles, but comparison returns false
You then try to only use c_str() method from the std::string :
stdString.c_str() == boostString // compiles, and comparison seems fine
You try the opposite out of curiosity and it works as well :
stdString == boostString.c_str() // compiles, and comparison seems fine
So the question is, why does these two latter comparisons seem to work fine when the first one did not ?
Bonus question : Is this an unreliable way of comparing the content of these strings ?
Full code sample :
#include <boost/container/string.hpp>
#include <iostream>
int main(int argc, char *argv[])
{
std::string stdString = "This is a test";
boost::container::string boostString;
for (int i = 0; i < 2; ++i)
{
if (i == 0)
{
boostString = "This is a test";
std::cout << "Both strings have the same content." << std::endl << std::endl;
}
else
{
boostString = "This is z test";
std::cout << std::endl << std::endl;
std::cout << "Both strings are different from each other." << std::endl << std::endl;
}
std::cout << "stdString.c_str() == boostString.c_str() comparison is : ";
if (stdString.c_str() == boostString.c_str())
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
std::cout << "stdString.c_str() == boostString comparison is : ";
if (stdString.c_str() == boostString)
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
std::cout << "stdString == boostString.c_str() comparison is : ";
if (stdString == boostString.c_str())
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
}
return 0;
}
Output given by the sample :
> Both strings have the same content.
>
> stdString.c_str() == boostString.c_str() comparison is : false
> stdString.c_str() == boostString comparison is : true
> stdString == boostString.c_str() comparison is : true
>
>
> Both strings are different from each other.
>
> stdString.c_str() == boostString.c_str() comparison is : false
> stdString.c_str() == boostString comparison is : false
> stdString == boostString.c_str() comparison is : false
With stdString.c_str() == boostString.c_str()
you don't compare the strings, you compare the pointers returned by each objects c_str
function. And they will most certainly not be equal. If you want to compare strings C-style use std::strcmp
.
The reason e.g. stdString.c_str() == boostString
works is because boost::container::string
have a non-explicit constructor taking a const char*
argument, just what stdString.c_str()
is returning. That means stdString.c_str() == boostString
is actually equal to boost::container::string(stdString.c_str()) == boostString
, which compares two boost::container::string
objects.
Same for stdString == boostString.c_str()
, it's equal to stdString == std::string(boostString.c_str())
.
If you need to mix std::string
and boost::container::string
, and need to use some specific operators with that mix, then you can always overload those operators yourself.
For example
bool operator==(std::string const& stdString, boost::container::string const& boostString)
{
// If the length of the strings differs, then they're not equal and we return false
// Otherwise, compare the actual contents of the strings
return stdString.length() == boostString.length() &&
std::memcmp(stdString.c_str(), boostString.c_str(), stdString.length()) == 0;
}
bool operator==(boost::container::string const& boostString, std::string const& stdString)
{
return stdString == boostString; // Calls the previously defined operator== overload
}
Both are needed so you can use either type on either side of ==
.
Also note that I'm using std::memcmp
for the comparison, because either string could contain embedded zeros, which would otherwise act as the string terminator for std::strcmp
.