Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Возвращение const char*


Автор: SaDFromSpb 20.7.2006, 15:05
Совершенно типичная задача: метод некоторого объекта возвращает строку описания кода ошибки:
Код

const char* SomeObject :: strerror(int errcode) {
   ostringstream oss;  // чтобы не париться с sprintf()
   switch (errcode) {
   case SO_WARN_SAVE_GRID : oss<<"Can't save grid for "<<spnum<<" shotpoint";    break;
   ...
   }
   return oss.str().c_str();
}

Здесь происходит не очень хорошая вещь: во "вне" выкидывается ссылка на объект области видимости функции strerror(), который может кануть в небытие в скором времени. Ведь так? Или же в данном случае, если полученная строка используется сразу же (до последующих вызовов функций по выделению памяти), то это не критично?
Но если писать полностью корректный код, то надо поступать по-честному. Заменить, например, строку
ostringstream oss; на ostringstream& oss = *(new ostringstream); (тогда получим висящий объект в куче) или сделать oss членом класса SomeObject... Тогда ситуация разрешится как с методом c_str() у string, который дает const-ссылку на внутренний буфер.

А может const - массивы все-равно остаются в стеке даже после выхода из области видимости и можно не париться (э... хотя вряд ли =) )? 

Автор: Fazil6 20.7.2006, 15:20
Цитата

Ведь так?

да.
обычно так.
Код

char* SomeObject :: strerror(int errcode, char * buf, int size) {
   ostringstream oss;  // чтобы не париться с sprintf()
   switch (errcode) {
   case SO_WARN_SAVE_GRID : oss<<"Can't save grid for "<<spnum<<" shotpoint";    break;
   ...
   }
   strncpy(buf, oss.str().c_str(), size - 1);
   buf[size - 1] = '\0';
   return buf;
}
  

Автор: SaDFromSpb 20.7.2006, 15:29
Fazil6, нда это конечно самый надежный вариант, просто хотелось сохранить семантику стандартного strerror() из <cstddef>
Только тогда уже лучше вот так:
Код
char* SomeObject :: strerror(int errcode, char** buff) {
   ostringstream oss;  // чтобы не париться с sprintf()
   switch (errcode) {
   case SO_WARN_SAVE_GRID : oss<<"Can't save grid for "<<spnum<<" shotpoint";    break;
   ...
   }
   const char* errmess = oss.str().c_str();
   *buff = new char[strlen(errmess) + 1];
   strcpy(*buff, errmess);
   return *buff;
}


Добавлено @ 15:32 
Кстати, strncpy() и так в buf допишет '\0'   

Автор: Fazil6 20.7.2006, 15:46
Цитата

Только тогда уже лучше вот так:

хм. Чем же это лучше?
Код

*buff = new char[strlen(errmess) + 1];

кто удалять это будет?
Цитата

Кстати, strncpy() и так в buf допишет '\0'  

если строка источника больше заданной для копирования, то не добавит

Добавлено @ 15:54 
Цитата

хотелось сохранить семантику стандартного strerror()


можно иметь какие-то константы вне функции и возвращать их 

Автор: SaDFromSpb 20.7.2006, 15:58
Fazil6,
Лучше тем, что не нужно производить мучительных раздумий, какой же длинны строку передавать в эту функцию. Нет ограничений на длинну строки, и лишняя память не используется.
Цитата(Fazil6 @  20.7.2006,  15:46 Найти цитируемый пост)
кто удалять это будет?

Так программер и будет.
Цитата(Fazil6 @  20.7.2006,  15:46 Найти цитируемый пост)
если строка источника больше заданной для копирования, то не добавит

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

Что-то мы уже здесь немного оффтопим.

Добавлено @ 16:00 
Цитата(Fazil6 @  20.7.2006,  15:46 Найти цитируемый пост)
можно иметь какие-то константы вне функции и возвращать их

Ты имеешь ввиду строковые константы? Так у нас же строки формируются внутри функции.  

Автор: SaDFromSpb 20.7.2006, 16:36
Ладно, закрываю эту глупую тему =) . 

Автор: UnrealMan 20.7.2006, 17:25
Цитата(SaDFromSpb @  20.7.2006,  15:05 Найти цитируемый пост)
ostringstream oss;

Сделай этот объект статическим – тогда до следующего обращения к функции SomeObject::strerror твоя строка будет в целости и сохранности. Только не забудь обнулять потоковую строку перед тем как туда что-то записывать (желательно это делать сразу после объявления static ostringstream oss; ). 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)