Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Я использую № 3: библиотека формата строки повышения - но я должен признать, что у меня никогда не было проблемы с различиями в спецификациях формата.
Работы как очарование для меня - и внешние зависимости могли быть хуже (очень стабильная библиотека)
Отредактированный: добавление примера, как использовать повышение:: формат вместо printf:
sprintf(buffer, "This is a string with some %s and %d numbers", "strings", 42);
было бы что-то вроде этого с повышением:: библиотека формата:
string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);
Hope это помогает разъяснить использование повышения:: формат
я использовал повышение:: формат как sprintf / printf замена в 4 или 5 приложениях (пишущий отформатированные строки в файлы или пользовательский вывод к файлам журнала) и никогда не имел проблемы с различиями в формате. Могут быть некоторые (более или менее неясные) спецификаторы формата, которые являются по-другому - но у меня никогда не было проблемы.
По контрасту у меня были некоторые спецификации формата, которые я не мог действительно сделать с потоками (так же, как я помню)
Вот идиома, которую я люблю за то, что то, что он делал функциональность идентичной 'sprintf', но возвратил станд.:: строка, и неуязвимый для проблем переполнения буфера. Этот код является частью проекта с открытым исходным кодом, который я пишу (лицензия BSD), таким образом, все не стесняются использовать это, как Вы желаете.
#include <string>
#include <cstdarg>
#include <vector>
#include <string>
std::string
format (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
std::string buf = vformat (fmt, ap);
va_end (ap);
return buf;
}
std::string
vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time.
size_t size = 1024;
char buf[size];
// Try to vsnprintf into our buffer.
va_list apcopy;
va_copy (apcopy, ap);
int needed = vsnprintf (&buf[0], size, fmt, ap);
// NB. On Windows, vsnprintf returns -1 if the string didn't fit the
// buffer. On Linux & OSX, it returns the length it would have needed.
if (needed <= size && needed >= 0) {
// It fit fine the first time, we're done.
return std::string (&buf[0]);
} else {
// vsnprintf reported that it wanted to write more characters
// than we allotted. So do a malloc of the right size and try again.
// This doesn't happen very often if we chose our initial size
// well.
std::vector <char> buf;
size = needed;
buf.resize (size);
needed = vsnprintf (&buf[0], size, fmt, apcopy);
return std::string (&buf[0]);
}
}
РЕДАКТИРОВАНИЕ: когда я написал этот код, я понятия не имел, что это потребовало соответствия C99 и что Windows (а также более старый glibc) имел другое vsnprintf поведение, в котором это возвращается-1 для отказа, а не категорической меры того, сколько пространства необходимо. Вот мой пересмотренный код, мог все просматривать его и если Вы будете думать, что он в порядке, то я отредактирую снова для создания этого единственной стоимостью перечисленный:
std::string
Strutil::vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time. Be prepared to allocate dynamically if it doesn't fit.
size_t size = 1024;
char stackbuf[1024];
std::vector<char> dynamicbuf;
char *buf = &stackbuf[0];
va_list ap_copy;
while (1) {
// Try to vsnprintf into our buffer.
va_copy(ap_copy, ap);
int needed = vsnprintf (buf, size, fmt, ap);
va_end(ap_copy);
// NB. C99 (which modern Linux and OS X follow) says vsnprintf
// failure returns the length it would have needed. But older
// glibc and current Windows return -1 for failure, i.e., not
// telling us how much was needed.
if (needed <= (int)size && needed >= 0) {
// It fit fine so we're done.
return std::string (buf, (size_t) needed);
}
// vsnprintf reported that it wanted to write more characters
// than we allotted. So try again using a dynamic buffer. This
// doesn't happen very often if we chose our initial size well.
size = (needed > 0) ? (needed+1) : (size*2);
dynamicbuf.resize (size);
buf = &dynamicbuf[0];
}
}
Можно использовать станд.:: строка и iostreams с форматированием, таким как setw () вызов и другие в iomanip
Следующее могло бы быть альтернативным решением:
void A::printto(ostream outputstream) {
char buffer[100];
string s = "stuff";
sprintf(buffer, "some %s", s);
outputstream << buffer << endl;
b.printto(outputstream);
}
(B::printto
подобный), и определяют
void A::print(FILE *f) {
printto(ofstream(f));
}
string A::to_str() {
ostringstream os;
printto(os);
return os.str();
}
, Конечно, необходимо действительно использовать snprintf вместо sprintf для предотвращения переполнения буфера. Вы могли также выборочно изменить более рискованный sprintfs на < < формат, чтобы быть более безопасным и все же измениться как можно меньше.
Необходимо попробовать библиотеку Loki заголовочный файл SafeFormat ( http://loki-lib.sourceforge.net/index.php?n=Idioms.Printf ). Это подобно библиотеке формата строки повышения, но сохраняет синтаксис printf (...) функционирует.
я надеюсь, что это помогает!
Это о сериализации? Или печать надлежащего? Если первый, рассмотрите повышение:: сериализация также. Это - все о "рекурсивной" сериализации объектов и подобъекта.