Указывает ли адрес результата std :: string :: operator [] на доступный для записи буфер с нулевым символом в конце? - PullRequest
2 голосов
/ 16 марта 2012

Я изменяю функцию, которая принимает const char * и использует функцию ProcessString. ProcessString - это функция, которая ожидает символьный буфер с нулевым символом в конце как char *. Символы в буфере могут или не могут быть изменены, как определено сигнатурой функции ниже. Чтобы «преодолеть разрыв», я использую временный std :: string:

void ProcessString( char* str );

void SomeFunction( const char* str )
{
  string temp(str);
  ProcessString( &temp[0] );
}

Мой основной вопрос касается гарантий std :: string :: operator [] и того, является ли адрес, возвращаемый вышеприведенным & temp [0], пригодным для использования буфером с нулевым символом в конце как char *. Во-вторых, и очень во-вторых, есть ли лучший способ сделать это?

Я использую C ++ 03.

Ответы [ 3 ]

5 голосов
/ 16 марта 2012

Это имеет только четко определенное поведение в C ++ 11; в предыдущих стандартах std::string не гарантировал непрерывное хранение для своего внутреннего буфера.

Однако, хотя этот код полностью подходит для C ++ 11, более идиоматический подход заключается в использовании std:vector<char>, который гарантирует непрерывное хранение с C ++ 03:

void ProcessString(char* str);

void SomeFunction(char const* str)
{
    // + 1 for terminating NUL
    std::vector<char> temp(str, str + std::strlen(str) + 1);
    ProcessString(&temp[0]); // or temp.data() in C++11
}
1 голос
/ 16 марта 2012

Я создал небольшой класс для решения этой проблемы, я реализовал идиому RAII.

class DeepString
{
        DeepString(const DeepString& other);
        DeepString& operator=(const DeepString& other);
        char* internal_; 

    public:
        explicit DeepString( const string& toCopy): 
            internal_(new char[toCopy.size()+1]) 
        {
            strcpy(internal_,toCopy.c_str());
        }
        ~DeepString() { delete[] internal_; }
        char* str() const { return internal_; }
        const char* c_str()  const { return internal_; }
};

И вы можете использовать его как:

void aFunctionAPI(char* input);

//  other stuff

aFunctionAPI("Foo"); //this call is not safe. if the function modified the 
                     //literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string 
                                                //implement reference counting and 
                                                //it may change the value of other
                                                //strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine

У меня естьвызвал класс DeepString, потому что он создает глубокую и уникальную копию (DeepString не копируется) существующей строки.

0 голосов
/ 16 марта 2012

Если вам нужно перейти от const char* к char *, почему бы не использовать strdup , а затем освободить буфер после завершения ProcessString?

Пройдите через std::string мне кажется ненужным.

...