Почему сравнение boost :: container :: string & std :: string не работает так, как задумано? - PullRequest
0 голосов
/ 21 января 2019

Допустим, у вас есть std :: string и boost :: container :: string, например:

std::string                stdString     =   "This is a test";
boost::container::string   boostString   =   "This is a test";

Допустим, вы хотите сравнить их содержимое;следующее невозможно, потому что мы не можем сравнивать их типы:

stdString == boostString                 // no operator "==" matches these operands

Затем вы решаете использовать оба их метода .c_str (), чтобы получить символ * из каждой строки.Не будучи уверенным, что это эффективно сравнивает строки, вы пытаетесь это сделать:

stdString.c_str() == boostString.c_str() // compiles, but comparison returns false

Затем вы пытаетесь использовать только метод c_str () из std :: string:

stdString.c_str() == boostString         // compiles, and comparison seems fine

Вы пробуете противоположное из любопытства, и оно также работает:

stdString == boostString.c_str()         // compiles, and comparison seems fine

Итак, вопрос в том, почему эти два последних сравнения, кажется, работают нормально, когда первое не сработало?

Дополнительный вопрос: Является ли это ненадежным способом сравнения содержимого этих строк?

Полный пример кода:

#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;
}

Вывод, предоставленный примером:

> 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

1 Ответ

0 голосов
/ 21 января 2019

С stdString.c_str() == boostString.c_str() вы не сравниваете строки, вы сравниваете указатели , возвращаемые каждой функцией c_str объектов.И они наверняка не будут равны.Если вы хотите сравнить строки в стиле C, используйте std::strcmp.


. Например, stdString.c_str() == boostString работает потому, что boost::container::string имеет неявный конструктор, принимающий const char* аргумент, то, что stdString.c_str() возвращает.Это означает, что stdString.c_str() == boostString фактически равен boost::container::string(stdString.c_str()) == boostString, что сравнивает два boost::container::string объекта.

То же самое для stdString == boostString.c_str(), это равно stdString == std::string(boostString.c_str()).


Есливам нужно смешать std::string и boost::container::string, и вам нужно использовать некоторые конкретные операторы с этим соединением, тогда вы всегда можете перегрузить эти операторы самостоятельно.

Например,

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
}

Обанеобходимы, чтобы вы могли использовать любой тип по обе стороны от ==.

Также обратите внимание, что я использую std::memcmp для сравнения, потому что любая строка может содержать встроенные нули,который в противном случае будет действовать как терминатор строки для std::strcmp.

...