Как бросить const char * exception?
От: Аноним  
Дата: 13.03.13 09:49
Оценка: -1
При возникновении нештатной ситуации хочу сформировать строку с описанием ошибки и передать ее как аргумент в исключение. Как правильно это сделать?

void foo()
{
   char exMsg[100];   

   // ... 
   sprintf( exMsg, "error: %s", err_descr );
   throw exMsg;
}


Вопросы.
1. Mожно ли так делать (передавать указатель на локальный буфер)?
2. Не нравится необходимость иметь массив на стеке, тем более заранее неизвестен размер. Как сделать кошерно?
Re: Как бросить const char * exception?
От: uzhas Ниоткуда  
Дата: 13.03.13 09:50
Оценка: 4 (1) +2 -3
Здравствуйте, Аноним, Вы писали:

А>Как сделать кошерно?


char exMsg[100];   
// ... 
sprintf( exMsg, "error: %s", err_descr );
throw std::exception(exMsg);
Re[2]: Как бросить const char * exception?
От: pkl  
Дата: 13.03.13 10:11
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Как сделать кошерно?


U>
U>char exMsg[100];   
U>// ... 
U>sprintf( exMsg, "error: %s", err_descr );
U>throw std::exception(exMsg);
U>


А разве объявленный автоматический char exMsg[100] не перестанет существовать после разматывания стека в ходе проброса исключения? Конечно, стек будет только разматываться, в него уже ничего не будет записано и лежащая в нём строка останется скорее всего невредимой, но выгдядит это по-хакерски.
Re[2]: Как бросить const char * exception?
От: saf_e  
Дата: 13.03.13 10:47
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Как сделать кошерно?


U>
U>char exMsg[100];   
U>// ... 
U>sprintf( exMsg, "error: %s", err_descr );
U>throw std::exception(exMsg);
U>


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

Поэтому тут выход только один хранит строку в объекте исключения, например использую std::runtime_error.
Re[3]: Как бросить const char * exception?
От: okman Беларусь https://searchinform.ru/
Дата: 13.03.13 11:03
Оценка: +2 -3
Здравствуйте, pkl, Вы писали:

char exMsg[100];   
// ... 
sprintf( exMsg, "error: %s", err_descr );
throw std::exception(exMsg);


pkl>А разве объявленный автоматический char exMsg[100] не перестанет существовать после разматывания стека


Перестанет. Но до того, как это произойдет, строка будет скопирована в экземпляр std::exception.
Поэтому такой код в этом плане полностью безопасен.
Re: Как бросить const char * exception?
От: PM  
Дата: 13.03.13 11:26
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>При возникновении нештатной ситуации хочу сформировать строку с описанием ошибки и передать ее как аргумент в исключение. Как правильно это сделать?


А>
А>void foo()
А>{
А>   char exMsg[100];   

А>   // ... 
А>   sprintf( exMsg, "error: %s", err_descr );
А>   throw exMsg;
А>}
А>


А>Вопросы.

А>1. Mожно ли так делать (передавать указатель на локальный буфер)?
А>2. Не нравится необходимость иметь массив на стеке, тем более заранее неизвестен размер. Как сделать кошерно?

0. В отличие от других языков, С++ позволят бросаться любым типом исключений, но практичнее использовать традиционный подход — бросать исключения, унаследованные из иерархии std::exception.

1. Как уже ответили, бросать в исключении указатель на локальный буфер нельзя. Общее правило таково, что из функции не надо возвращать каким-либо образом указатели на локальные переменные.

2. Если использовать массив фиксированного размера и sprintf("%s"), то рано или поздно получишь переполнение буфера (повезет, если рано и получишь ты, а не взломщик сервера). Для форматирования использовать std::stringstream, boost::format и т.п. В простейшем случае может хватить std::string:

void foo()
{
   if ( some_failure )
   {
       std::string err_msg = std::string("error: ") + err_descr;
       throw std::runtime_error(err_msg); // или еще какой-нибудь потомок std::exception
   }
}
Re[2]: Как бросить const char * exception?
От: jyuyjiyuijyu  
Дата: 13.03.13 11:28
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Аноним, Вы писали:


А>>Как сделать кошерно?


U>
U>char exMsg[100];   
U>// ... 
U>sprintf( exMsg, "error: %s", err_descr );
U>throw std::exception(exMsg);
U>


так вроде безопаснее... хотя если не хватит памяти...

U>
U>throw ( boost::format( "error: %s" ) % err_descr ) .str().c_str();
U>
Re[4]: Как бросить const char * exception?
От: Evgeny.Panasyuk Россия  
Дата: 13.03.13 11:29
Оценка: +2
Здравствуйте, okman, Вы писали:

u>>throw std::exception(exMsg);

O>Перестанет. Но до того, как это произойдет, строка будет скопирована в экземпляр std::exception.
O>Поэтому такой код в этом плане полностью безопасен.

MSVC — не единственный компилятор
C++03, 18.6.1
namespace std {
    class exception {
    public:
        exception() throw();
        exception(const exception&) throw();
        exception& operator=(const exception&) throw();
        virtual ~exception() throw();
        virtual const char* what() const throw();
    };
}
Re[4]: Как бросить const char * exception?
От: PM  
Дата: 13.03.13 11:37
Оценка: +1
Здравствуйте, okman, Вы писали:

O>Здравствуйте, pkl, Вы писали:


O>
O>char exMsg[100];   
O>// ... 
O>sprintf( exMsg, "error: %s", err_descr );
O>throw std::exception(exMsg);
O>


pkl>>А разве объявленный автоматический char exMsg[100] не перестанет существовать после разматывания стека


O>Перестанет. Но до того, как это произойдет, строка будет скопирована в экземпляр std::exception.

O>Поэтому такой код в этом плане полностью безопасен.

Вообще-то у std::exception нет конструктора, принимающего char* или std::string.

Код с использованием sprintf("%s") не может считаться безопасным.
Re[5]: Как бросить const char * exception?
От: okman Беларусь https://searchinform.ru/
Дата: 13.03.13 11:50
Оценка: +3
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>MSVC — не единственный компилятор


Ок, заменим std::exception на std::runtime_error.
Re[5]: Как бросить const char * exception?
От: okman Беларусь https://searchinform.ru/
Дата: 13.03.13 11:52
Оценка: -1
Здравствуйте, PM, Вы писали:

PM>Код с использованием sprintf("%s") не может считаться безопасным.


pkl>>А разве объявленный автоматический char exMsg[100] не перестанет существовать после разматывания стека

O>Перестанет. Но до того, как это произойдет, строка будет скопирована в экземпляр std::exception.
O>Поэтому такой код в этом плане полностью безопасен.

Re[5]: Как бросить const char * exception?
От: uzhas Ниоткуда  
Дата: 13.03.13 12:20
Оценка: :)))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>MSVC — не единственный компилятор

студия схавала мой мозг
Re: Как бросить const char * exception?
От: Alexéy Sudachén Чили  
Дата: 13.03.13 12:44
Оценка:
А>2. Не нравится необходимость иметь массив на стеке, тем более заранее неизвестен размер. Как сделать кошерно?

Если без помощи асфальтоукладочного катка, то где-то так:

#include <stdarg.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <sstream>
#include <iomanip>

std::string sformat(char *fmt, ...) {
    va_list va;
    va_start(va,fmt);
    std::vector<char> buf(_vscprintf(fmt,va)+1);
    vsprintf(&buf[0],fmt,va);
    va_end(va);    
    return std::string(&buf[0]);
}

int fa() {
    throw std::runtime_error( sformat("fa adderss %p",fa) );
}

int fb() {
    throw sformat("fb adderss %p",fb);
}

int fc() {
    std::stringstream ss; 
    ss << "fc adderss " << std::hex << fc;
    throw /*std::runtime_error(*/ ss.str() /*)*/;
}

int main()
{
    try { 
        fc();
    }catch(std::string &e) { 
        printf("error:%s",e.c_str());
    }catch(std::exception &e) { 
        printf("error:%s",e.what());
    } 
}


Выбирай что больше нравится.
Re[3]: Как бросить const char * exception?
От: Erop Россия  
Дата: 14.03.13 13:03
Оценка:
Здравствуйте, saf_e, Вы писали:

_>Поэтому тут выход только один хранит строку в объекте исключения, например использую std::runtime_error.


Ещё можно в статический std::string, например, сложить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Как бросить const char * exception?
От: wander  
Дата: 14.03.13 17:19
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

U>>
U>>throw ( boost::format( "error: %s" ) % err_descr ) .str().c_str();
U>>


Временный объект std::string, c_str() у него, потом разрушение std::string — бамс!, в catch прилетает невалидный пойнтер.
Знал бы ты сколько такой херни мне пришлось видеть и исправлять. Не делайте так. Пожалуйста.
объект std::string
Re[4]: Как бросить const char * exception?
От: saf_e  
Дата: 14.03.13 17:58
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, saf_e, Вы писали:


_>>Поэтому тут выход только один хранит строку в объекте исключения, например использую std::runtime_error.


E>Ещё можно в статический std::string, например, сложить...


Ну статический не подойдет, а вот per-thread уже вполне
Re[2]: Как бросить const char * exception?
От: enji  
Дата: 16.03.13 07:18
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>

AS>std::string sformat(char *fmt, ...) {
AS>    va_list va;
AS>    va_start(va,fmt);
AS>    std::vector<char> buf(_vscprintf(fmt,va)+1);
AS>    vsprintf(&buf[0],fmt,va);
AS>    va_end(va);    
AS>    return std::string(&buf[0]);
AS>}

AS>

А зачем этот изврат с форматированием?
Взять boost::format или stringstream. Исключения кидаются редко, экономить на форматировании смысла нет
Re[3]: Как бросить const char * exception?
От: Alexéy Sudachén Чили  
Дата: 16.03.13 12:59
Оценка:
E>А зачем этот изврат с форматированием?
E>Взять boost::format или stringstream. Исключения кидаются редко, экономить на форматировании смысла нет

stringstream в примере есть, но он патологически неудобен, а что до сисек ... не все знаете ли любят тяжёлые наркотики, некоторые предпочитают лёгкие )))
Re[4]: Как бросить const char * exception?
От: enji  
Дата: 16.03.13 19:03
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

E>>А зачем этот изврат с форматированием?

E>>Взять boost::format или stringstream. Исключения кидаются редко, экономить на форматировании смысла нет

AS>stringstream в примере есть, но он патологически неудобен, а что до сисек ... не все знаете ли любят тяжёлые наркотики, некоторые предпочитают лёгкие )))


что такое сиськи? Новое название буста?

Просто ошибешься ты в форматной строке или передашь в твою функцию не POD — будет не здорово...

stringstream кстати для исключений довольно удобен, ИМХО. Неудобен он, когда нужно что-то форматировать (манипуляторы — ужас). А когда надо просто загнать какую-то инфу в строку и на форматирование плевать (эксепшены, логирование) — поудобнее принтфа. А если использовать свой stringstream, отвязанный от локали — еще и быстрее
Re[5]: Как бросить const char * exception?
От: Alexéy Sudachén Чили  
Дата: 16.03.13 20:06
Оценка:
AS>>stringstream в примере есть, но он патологически неудобен, а что до сисек ... не все знаете ли любят тяжёлые наркотики, некоторые предпочитают лёгкие )))
E>что такое сиськи? Новое название буста?

Очень даже старое )))

E>Просто ошибешься ты в форматной строке или передашь в твою функцию не POD — будет не здорово...


То мне об этом скажет компилятор ))) И в весьма читабельном виде.

#include <stdio.h>

struct A {
   char S[10];
};

struct A a = { "hello" };

int main() {
    printf("%s world\n",a);
}


cl: warning C6284: Object passed as parameter '2' when string is required in call to 'printf'
gcc: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'struct A'

а чего там скажет форматтер сисек после чайной паузы на время компиляции?
#include <boost/format.hpp>
using namespace std;

struct A { 
   char a[10]; 
};

A a = { "hello" };

int main() {
   cout << boost::format("%s world") % a << endl;
}


  Скрытый текст
boost/format/feed_args.hpp(100) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const A' (or there is no acceptable conversion)
        include\ostream(679): could be 'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const char *)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(726): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,char)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(764): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const char *)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(811): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,char)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(937): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const signed char *)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(944): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,signed char)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(951): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const unsigned char *)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(958): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,unsigned char)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(968): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>,T>(std::basic_ostream<_Elem,_Traits> &&,_Ty)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>,
            T=A,
            _Ty=A
        ]
        include\ostream(1085): or       'std::basic_ostream<_Elem,_Traits> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const std::error_code &)' [found using argument-dependent lookup]
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        boost/format/group.hpp(45): or       'std::basic_ostream<_Elem,_Traits> &boost::io::detail::operator <<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const boost::io::detail::group0 &)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(186): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(std::basic_ostream<_Elem,_Traits> &(__cdecl *)(std::basic_ostream<_Elem,_Traits> &))'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(192): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(std::basic_ios<_Elem,_Traits> &(__cdecl *)(std::basic_ios<_Elem,_Traits> &))'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(199): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(std::ios_base &(__cdecl *)(std::ios_base &))'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(206): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(std::_Bool)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(226): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(short)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(260): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(unsigned short)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(280): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(int)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(305): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(unsigned int)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(325): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(long)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(345): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(unsigned long)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(366): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(__int64)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(386): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(unsigned __int64)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(407): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(float)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(427): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(double)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(447): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(long double)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(467): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(const void *)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        include\ostream(487): or       'std::basic_ostream<_Elem,_Traits> &std::basic_ostream<_Elem,_Traits>::operator <<(std::basic_streambuf<_Elem,_Traits> *)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        while trying to match the argument list '(std::basic_ostream<_Elem,_Traits>, const A)'
        with
        [
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        boost/format/feed_args.hpp(159) : see reference to function template instantiation 'void boost::io::detail::put_last<char,std::char_traits<char>,T>(std::basic_ostream<_Elem,_Traits> &,const T &)' being compiled
        with
        [
            T=A,
            _Elem=char,
            _Traits=std::char_traits<char>
        ]
        boost/format/feed_args.hpp(254) : see reference to function template instantiation 'void boost::io::detail::put<Ch,Tr,Alloc,T>(T,const boost::io::detail::format_item<Ch,Tr,Alloc> &,std::basic_string<_Elem,_Traits,_Ax> &,boost::io::basic_altstringbuf<Ch,Tr,Alloc> &,boost::io::detail::locale_t *)' being compiled
        with
        [
            Ch=char,
            Tr=std::char_traits<char>,
            Alloc=std::allocator<char>,
            T=const A &,
            _Elem=char,
            _Traits=std::char_traits<char>,
            _Ax=std::allocator<char>
        ]
        boost/format/feed_args.hpp(263) : see reference to function template instantiation 'void boost::io::detail::distribute<Ch,Tr,Alloc,T>(boost::basic_format<Ch> &,T)' being compiled
        with
        [
            Ch=char,
            Tr=std::char_traits<char>,
            Alloc=std::allocator<char>,
            T=const A &
        ]
        boost/format/format_class.hpp(64) : see reference to function template instantiation 'boost::basic_format<Ch> &boost::io::detail::feed<char,Tr,Alloc,const T&>(boost::basic_format<Ch> &,const A)' being compiled
        with
        [
            Ch=char,
            Tr=std::char_traits<char>,
            Alloc=std::allocator<char>,
            T=A
        ]
        3.cpp(9) : see reference to function template instantiation 'boost::basic_format<Ch> &boost::basic_format<Ch>::operator %<A>(const T &)' being compiled
        with
        [
            Ch=char,
            T=A
        ]

Типа такая вот демонстрация KISS в жизни.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.