Как поделиться глобальными константами с минимальными издержками во время выполнения? - PullRequest
4 голосов
/ 03 апреля 2019

Я использую C ++ 11.Мне запрещено использовать внешние библиотеки, такие как boost и т. Д. Я должен использовать только STL.

У меня есть ряд событий, которые должны быть определены как строковые константы.Мне не разрешено использовать перечисления или целые числа или любой другой тип данных.Например:

"имя-события1"

"имя-события2"

"some_other_event_name3"

"a_different_event_name12"

Затем у меня есть несколько классов, которым нужно использовать эти строки, но я не знаю, существуют ли другие классы (они не имеют никакого отношения друг к другу).

class Panel{

    void postEvent(){
        SomeSingleton::postEvent("event_name");
    }
}

Другой класс ::

class SomeClass{

    SomeClass(){
        SomeSingleton::listenForEvent("event_name");
    }

    void receiveEvent(){
         //This function is triggered when "event_name" occurs.
         //Do stuff
    }
}

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

Вот что я пробовал:

Как хранить строкиконстанты, к которым будет обращаться несколько разных классов?

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

Как сохранить строки в общем файле, чтобы все другие классы, использующие эти строки, могли ссылаться на один и тот же файл?

  • Я не хочутратить память или утечка памяти в течение жизни моего приложения (это яobile app)
  • время компиляции не имеет для меня большого значения, так как проект не такой большой
  • ожидается, что может быть 50 различных событий.
  • ItКажется, было бы удобнее сохранить все строки в одном файле и редактировать только этот файл по мере изменения ситуации.
  • Любой класс может прослушивать любое событие в любое время, и я не буду знатьдо компиляции

Ответы [ 5 ]

8 голосов
/ 03 апреля 2019

Самый простой способ - использовать константу char const*, так как она более оптимизируема и не использует динамическое распределение.

Также вы можете использовать std::string_view в функции postEvent, избегая динамического распределения. Этот шаг не является обязательным. Если вы не можете иметь строковые представления и по-прежнему хотите избежать динамического распределения, обратитесь к максимальной емкости SSO вашей реализации и оставьте имена событий ниже этого размера.

Также учтите, что nonstd::string_view может поставляться как библиотека C ++ 11 и, скорее всего, необходимая вам абстракция. Такие библиотеки, как cpp17_headers и string-view-lite существуют исключительно для этой цели.

Это выглядит так:

constexpr auto event_name1 = "event_name1";

В классе как статический член он работает так же:

struct Type {
    static constexpr auto event_name1 = "event_name1";
};

Это займет максимум места в статических данных только для чтения вашего исполняемого файла.

4 голосов
/ 03 апреля 2019

В свете того факта, что вы застряли на C ++ 11, я думаю, что мое предложение от здесь все еще остается в силе:

#ifndef INCLUDED_EVENT_NAMES
#define INCLUDED_EVENT_NAMES

#pragma once

namespace event_names
{
    constexpr auto& event_1 = "event_1";
    constexpr auto& event_2 = "event_2";
}

#endif

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

Если бы вы могли использовать C ++ 17, я бы предложил использовать подход std::string_view, но в C ++ 11 я думаю, что вышеупомянутое, скорее всего, является хорошим компромиссом для вашего приложения.

3 голосов
/ 03 апреля 2019

Global const std::string имеет один недостаток, который необходимо обработать во время запуска, и создает копию строкового литерала.

Для связанного ответа SO используется constexpr std::string_view, и это классное решение, поскольку конструктор constexpr, поэтому ничего не нужнодолжно быть сделано при запуске.Также это не создает никакой копии.Проблема в том, что это C ++ 17

Использование const char [] (или auto или constexpr) является старым проверенным решением.Вы можете сравнить std::string с ним без каких-либо дополнительных затрат.

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

2 голосов
/ 03 апреля 2019

Вы можете иметь структуру статических строк:

struct MyNames
{
    static const std::string name1;
};

И в cpp:

const std::string MyNames::name1 = "foo";

Вы можете получить доступ к именам из всех ваших необходимых мест.В C ++ 17 вы бы вместо этого использовали string_view, чтобы избежать конструирования объекта.Но это, кажется, дубликат этого ответа, в основном: https://stackoverflow.com/a/55493109/2266772

1 голос
/ 03 апреля 2019

Ради правильной абстракции и хорошего дизайна вы должны определить класс событий . Этот класс событий будет иметь либо:

  • Метод, который предоставляет строку (например, name() или system_name())
  • Оператор преобразования в строку (не рекомендуется)
  • A to_string() автономная функция, которая принимает такое событие (не рекомендуется)

Но помимо этого - все ваши классы могут теперь использовать enum, или индекс, или что им нравится - им просто нужно будет использовать метод преобразования всякий раз, когда они взаимодействуют с чем бы то ни было требует строк. Таким образом, ни один из ваших классов не должен знать об этих строках сам.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...