В C ++, как класс может получить const std :: string & параметр в конструкторе, но также обрабатывать NULL? - PullRequest
4 голосов
/ 22 октября 2009

Я пытаюсь найти способы создания класса с аргументом std :: string, но он также обрабатывает NULL без исключения. Вот пример кода:

class myString {
public:
    myString(const std::string& str) : _str(str) {}
    std::string _str;
};

int main() {
    myString mystr(NULL);
    printf("mystr = <%s>\n", mystr._str.c_str());
    return 0;
}

Интуитивно, вы думаете, что эта программа должна напечатать "mystr = <>" и успешно завершиться, но вместо этого с g ++ выдает эту ошибку:

terminate called after throwing an instance of 'std::logic_error'  
what():  basic_string::_S_construct NULL not valid

Как я могу изменить этот класс так, чтобы он переводил NULL в "" вместо генерирования исключения logic_error?

(Постскриптум: как вы и подозреваете, «реальная» реализация немного сложнее, чем этот пример, с несколькими аргументами в конструкторе и более интересными вещами с _str - и с должным сохранением конфиденциальности. Мотивация этот пример показывает, что программисты в нашей команде будут склонны использовать NULL в этом контексте для исторических целей, и компилятор не поймает этого. Переучить каждого всегда использовать "" довольно сложно. В противном случае было бы легко найти умное решение)

Ответы [ 5 ]

11 голосов
/ 22 октября 2009

На самом деле здесь происходит то, что NULL интерпретируется как char const* и его пытаются преобразовать в std::string (вы можете преобразовать C-строки типа char* в строки STL, верно?).

Чтобы справиться с этим, вы можете добавить еще один конструктор

class myString {
public:
    myString(const std::string& str) : _str(str) {}
    myString(const char* str) : _str(str==NULL?"":std::string(str)) 
    { /* and do something special in the body */ }
    std::string _str;
};

Но если вам не нужно ничего особенного, лучшим способом будет

class myString {
public:
    myString(const std::string& str = "") : _str(str) {}
    std::string _str;
};
int main() {
    myString mystr;  //no () here!
    printf("mystr = <%s>\n", mystr._str.c_str());
    return 0;
}
6 голосов
/ 22 октября 2009

На самом деле, вы не можете. NULL не является строкой. Но вот несколько альтернатив:

  • Вы можете перегрузить ваш конструктор опустить строковый аргумент.

  • Вы можете использовать указатель вместо ссылка.

  • Вы можете использовать строковый аргумент по умолчанию в "".

5 голосов
/ 22 октября 2009

Вы не можете. Вам нужно что-то, чтобы иметь возможность передать ссылку. Однако вы можете обойти это, по умолчанию установив нулевые строки, такие как "".

В качестве альтернативы, есть еще explicit ctor:

class myString {
 public:
   myString(const std::string& str) : _str(str) {}
   explicit myString(const char* str = NULL) : _str(str?str:"") {}
   std::string _str;
};
2 голосов
/ 22 октября 2009

Вам необходимо предоставить конструктор, который принимает указатель в качестве аргумента. NULL - это указатель, а не ссылка, и, как вы увидели, катастрофа приведет к тому, что вы попытаетесь обработать ее как строковую ссылку.

Попытка:

class myString {
public:
    myString(const std::string& str) : _str(str) {}
    myString(const std::string* str) : { /* special-case logic here */}
    std::string _str;
};
0 голосов
/ 22 октября 2009

Полагаю, эта проблема не так проста, как кажется в вашем примере.

Вместо использования параметра NULL вы можете создать статическую переменную и присвоить ей значение.

class myString {
public:
    static std::string nullstring;
...
};

и где-то в .cpp:

std::string myString::nullstring("");

И назвать это:

int main() {
    myString mystr(myString::nullstring);
    printf("mystr = <%s>\n", mystr._str.c_str());
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...