2010-07-20 2 views
1

У меня есть этот код внутри конструктора класса (не написанный мной), и он записывает переменный список arg в файл tmp.var arg список tempfile, зачем он нужен?

Я задавался вопросом, зачем это нужно? Tmpfile удаляется после того, как этот ctor выходит из области видимости, а список var arg находится внутри вектора m_str.

Может ли кто-нибудь предложить лучший способ сделать это без использования tmpfile?

DString(const char *fmt, ...) 
    { 

     DLog::Instance()->Log("Inside DString with ellipses"); 

     va_list varptr; 
     va_start(varptr, fmt); 
     FILE *f = tmpfile(); 
     if (f != NULL) 
     { 
      int n = ::vfprintf(f, fmt, varptr) + 1; 
      m_str.resize(n + 1); 
      ::vsprintf(&m_str[0], fmt, varptr); 
      va_end(varptr); 
     } 
     else 
      DLog::Instance()->Log("[ERROR TMPFILE:] Unable to create TmpFile for request!"); 
    } 
+0

Можете ли вы изменить прототип конструктора, чтобы избежать использования эллипсов? – ereOn

+0

ereOn: Без причины. Это привело бы к множеству ошибок в моей кодовой базе. –

+0

Если 'm_str' - это' std :: string', то обработка '& m_str [0]' как указателя на массив дает неопределенное поведение; хранение не гарантируется, что оно будет смежным.Если это 'std :: vector ', то это нормально. –

ответ

2

Это код C++: Я думаю, что вы, возможно, пытается решить проблему неправильно здесь.

Необходимость в временном файле полностью исчезнет, ​​если вы захотите использовать конструкцию C++-esque, вместо того чтобы продолжать использовать varargs. Может показаться, что большая часть работы заключается в том, чтобы преобразовать все вызывающие сайты в новый механизм, но varargs предоставляют множество возможностей для пропусков параметров, оставляя вас открытыми для коварных ошибок, не говоря уже о том, POD вообще. Я верю, что в долгий (или даже средний) срок он окупится в надежности, ясности и простоте отладки.

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

1

Это просто используя временный файл как место, которое он может записать содержимое, которое не будет переполнение, так что он может измерить длину, а затем выделить достаточное пространство для строки, и, наконец, внести реальный выход в Струна.

я бы по крайней мере, насколько трудно было бы заменить текущий интерфейс Printf-стиля, ведущий к этому с интерфейсом iostreams стиля, который позволит легко избежать и дают все обычные преимущества iostreams (тип-безопасный, расширяемый и т. д.)

Редактировать: если изменение подписи функции действительно сложно рассмотреть, то вы, вероятно, захотите заменить vfprintf на vsnprintf. vsnprintf позволяет указать длину буфера (чтобы он не перекрывал буфер), и он возвращает количество символов, которое было бы, если бы было достаточно места. Таким образом, использование будет почти таким, как вы сейчас, но не создавайте временный файл. Вы бы назвали его, указав длину буфера 0, используйте возвращаемое значение (+1 для терминатора NUL) для изменения размера вашего буфера, а затем снова вызовите его, указав правильный размер буфера.

+0

Можно ли заменить его, не меняя подпись этого контрагента? –

+0

@ Тони: да. 'n = vsnprintf (0, 0, fmt, varptr) + 1' даст вам длину, не разбираясь с временными файлами. –

0

Похоже, что файл temp используется в качестве места вывода для вызова :: vfprintf(). Он делает это, чтобы получить длину отформатированной строки (плюс 1 для NULL). Затем изменяет размер m_str достаточно большим, чтобы удерживать форматированную строку, которая заполняется из вызова :: vsprintf().

Список переменных arg отсутствует в файле или в m_str. Отформатированный вывод printf() (и его вариантов) находится в файле и в m_str.

0

У меня есть тошнотворное чувство, показывая это, но вы можете попробовать:

FILE *fp=freopen("nul","w", stderr) 
    int n = ::vfprintf(fp , fmt, varptr); 
    fclose(fp); 

(окна)

Смежные вопросы