Какое безопасное с точки зрения типов перечисление в C++ Вы Используете?

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, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

44
задан Sebastian Mach 16 June 2014 в 20:37
поделиться

8 ответов

Я в настоящее время играю вокруг с Повышением. Перечислимое предложение от Хранилище Повышения (имя файла 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();
        }
    }
};

Это удовлетворяет все пять из приоритетов, которые Вы перечисляете.

42
ответ дан pesche 26 November 2019 в 22:05
поделиться

Хороший метод компромисса - это:

struct Flintstones {
   enum E {
      Fred,
      Barney,
      Wilma
   };
};

Flintstones::E fred = Flintstones::Fred;
Flintstones::E barney = Flintstones::Barney;

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

18
ответ дан Charlie 26 November 2019 в 22:05
поделиться

Я использую C++ 0x безопасные с точки зрения типов перечисления . Я использую некоторый шаблон/макросы помощника, которые обеспечивают для строкового представления функциональности.

enum class Result { Ok, Cancel};
12
ответ дан Roddy 26 November 2019 в 22:05
поделиться

Я не делаю. Слишком много служебное для небольшого преимущества. Кроме того, способность к кастовым перечислениям к различным типам данных для сериализации является очень удобным инструментом. Я никогда не видел экземпляр, где "Безопасное с точки зрения типов" перечисление стоило бы издержек и сложности, где C++ уже предлагает достаточно хорошую реализацию.

6
ответ дан 26 November 2019 в 22:05
поделиться

Мое взятие - то, что Вы изобретаете проблему и затем соответствуете решению на него. Я не вижу потребности сделать тщательно продуманную платформу для перечисления значений. Если Вы , выделил наличию Ваших значений, только члены определенного набора, Вы могли изрубить вариант уникального типа данных набора.

2
ответ дан Paul Nathan 26 November 2019 в 22:05
поделиться

Я думаю, что 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 интерфейс и работает как наборы---, но реализованные битовые маски использования). Намного более читаемый, чем рукописное управление битовой маской!

1
ответ дан Chris Jester-Young 26 November 2019 в 22:05
поделиться

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

оборотная сторона моего подхода - то, что он программно не осуществляет связь между перечислением и классом помощника, таким образом, они должны быть обновлены параллельно. Это работает на меня, но YMMV.

1
ответ дан Community 26 November 2019 в 22:05
поделиться

Не уверен, что эта публикация слишком поздно, но на GameDev.net есть статья, которая удовлетворяет всем, кроме 5-го пункта (возможность итерации по счетчикам): http://www.gamedev.net/reference/snippets/features/cppstringizing/

Метод, описанный в статье, позволяет поддерживать преобразование строк для существующих перечислений без изменения их кода. Если же вам нужна поддержка только новых перечислений, я бы выбрал Boost.Enum (упомянутый выше).

-2
ответ дан 26 November 2019 в 22:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: