NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Я в настоящее время играю вокруг с Повышением. Перечислимое предложение от Хранилище Повышения (имя файла enum_rev4.6.zip
). Хотя это официально никогда не отправлялось для включения в Повышение, это применимо как есть. (Документация недостает, но восполнена ясным исходным кодом и хорошими тестами.)
Повышение. Перечисление позволяет Вам объявить перечисление как это:
BOOST_ENUM_VALUES(Level, const char*,
(Abort)("unrecoverable problem")
(Error)("recoverable problem")
(Alert)("unexpected behavior")
(Info) ("expected behavior")
(Trace)("normal flow of execution")
(Debug)("detailed object state listings")
)
И имеют его, автоматически расширяются до этого:
class Level : public boost::detail::enum_base<Level, string>
{
public:
enum domain
{
Abort,
Error,
Alert,
Info,
Trace,
Debug,
};
BOOST_STATIC_CONSTANT(index_type, size = 6);
Level() {}
Level(domain index) : boost::detail::enum_base<Level, string>(index) {}
typedef boost::optional<Level> optional;
static optional get_by_name(const char* str)
{
if(strcmp(str, "Abort") == 0) return optional(Abort);
if(strcmp(str, "Error") == 0) return optional(Error);
if(strcmp(str, "Alert") == 0) return optional(Alert);
if(strcmp(str, "Info") == 0) return optional(Info);
if(strcmp(str, "Trace") == 0) return optional(Trace);
if(strcmp(str, "Debug") == 0) return optional(Debug);
return optional();
}
private:
friend class boost::detail::enum_base<Level, string>;
static const char* names(domain index)
{
switch(index)
{
case Abort: return "Abort";
case Error: return "Error";
case Alert: return "Alert";
case Info: return "Info";
case Trace: return "Trace";
case Debug: return "Debug";
default: return NULL;
}
}
typedef boost::optional<value_type> optional_value;
static optional_value values(domain index)
{
switch(index)
{
case Abort: return optional_value("unrecoverable problem");
case Error: return optional_value("recoverable problem");
case Alert: return optional_value("unexpected behavior");
case Info: return optional_value("expected behavior");
case Trace: return optional_value("normal flow of execution");
case Debug: return optional_value("detailed object state listings");
default: return optional_value();
}
}
};
Это удовлетворяет все пять из приоритетов, которые Вы перечисляете.
Хороший метод компромисса - это:
struct Flintstones {
enum E {
Fred,
Barney,
Wilma
};
};
Flintstones::E fred = Flintstones::Fred;
Flintstones::E barney = Flintstones::Barney;
Это не безопасно с точки зрения типов в том же смысле, который Ваша версия, но использование более хорошо, чем стандартные перечисления, и можно все еще использовать в своих интересах целочисленное преобразование при необходимости в нем.
Я использую C++ 0x безопасные с точки зрения типов перечисления . Я использую некоторый шаблон/макросы помощника, которые обеспечивают для строкового представления функциональности.
enum class Result { Ok, Cancel};
Я не делаю. Слишком много служебное для небольшого преимущества. Кроме того, способность к кастовым перечислениям к различным типам данных для сериализации является очень удобным инструментом. Я никогда не видел экземпляр, где "Безопасное с точки зрения типов" перечисление стоило бы издержек и сложности, где C++ уже предлагает достаточно хорошую реализацию.
Мое взятие - то, что Вы изобретаете проблему и затем соответствуете решению на него. Я не вижу потребности сделать тщательно продуманную платформу для перечисления значений. Если Вы , выделил наличию Ваших значений, только члены определенного набора, Вы могли изрубить вариант уникального типа данных набора.
Я думаю, что Java enum
был бы хорошей моделью для следования. По существу форма Java была бы похожа на это:
public enum Result {
OK("OK"), CANCEL("Cancel");
private final String name;
Result(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
то, Что интересно о подходе Java, - то, что OK
и CANCEL
неизменны, одноэлементные экземпляры Result
(с методами, которые Вы видите). Вы не можете создать дальнейшие экземпляры Result
. Так как они - одиночные элементы, можно выдержать сравнение указателем/ссылкой---очень удобный.:-)
ЭТА: В Java, вместо того, чтобы делать битовые маски вручную, вместо этого Вы используете EnumSet
для определения небольшого набора (это реализует эти Set
интерфейс и работает как наборы---, но реализованные битовые маски использования). Намного более читаемый, чем рукописное управление битовой маской!
Я дал ответ на это здесь по различной теме. Это - различный стиль подхода, который позволяет большую часть той же функциональности, не требуя модификации к исходному перечислимому определению (и следовательно позволяя использование в случаях, где Вы не определяете перечисление). Это также позволяет проверку диапазона во время выполнения.
оборотная сторона моего подхода - то, что он программно не осуществляет связь между перечислением и классом помощника, таким образом, они должны быть обновлены параллельно. Это работает на меня, но YMMV.
Не уверен, что эта публикация слишком поздно, но на GameDev.net есть статья, которая удовлетворяет всем, кроме 5-го пункта (возможность итерации по счетчикам): http://www.gamedev.net/reference/snippets/features/cppstringizing/
Метод, описанный в статье, позволяет поддерживать преобразование строк для существующих перечислений без изменения их кода. Если же вам нужна поддержка только новых перечислений, я бы выбрал Boost.Enum (упомянутый выше).