Предотвращение глобальных переменных во встроенном программировании

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

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

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

7
задан Nate Parsons 14 August 2009 в 01:13
поделиться

3 ответа

Вы можете использовать элемент [id $ = Идентификатор], который ищет идентификатор, заканчивающийся указанным вами текстом (это идентификатор, который вы указываете в разметке ASPX). Вот пример, показывающий, как вы можете его использовать (см. Слайд № 30): Создание приложений интрасети с помощью ASP.NET AJAX и jQuery .

без фреймворка это может наложить некоторую ответственность на клиентский код. Но это действительно помогает тестированию. Например, для проверки FSW_taskStart ()

tThreadConfig threadConfig[NUM_THREADS] = {
  { "Foo 1", %foo1, 0, ... },
  { "Foo 2", %foo2, 0, ... },
  { "Task",  %task, 0, ... }
};

void FSW_taskStart(tThreadConfig configs[], size_t len) {
    for (int i = 0; i < len; i++) {
        configs[i].taskptr->createThread(  );
    }
}

void FSW_taskStart() {
    FSW_taskStart(tThreadConfig, NUM_THREADS);
}

void testFSW_taskStart() {
    MockTask foo1, foo2, foo3;
    tThreadConfig mocks[3] = {
          { "Foo 1", &foo1, 0, ... },
          { "Foo 2", &foo2, 0, ... },
          { "Task",  &foo3, 0, ... }
        };
    FSW_taskStart(mocks, 3);
    assert(foo1.started);
    assert(foo2.started);
    assert(foo3.started);
}

Теперь вы можете передать фиктивную версию ваших потоков в 'FSW_taskStart', чтобы убедиться, что функция действительно запускает потоки по мере необходимости. К сожалению, вы должны полагаться на тот факт, что исходный FSW_taskStart передает правильные аргументы, но теперь вы тестируете гораздо больше своего кода.

4
ответ дан 7 December 2019 в 10:05
поделиться

Вы можете выделить память с помощью malloc, а затем получить новый оператор для создания объекта в этой позиции

void* mem = malloc(3*sizeof(SomeClass));
SomeClass *a = new(mem) SomeClass();
mem += sizeof(SomeClass);
SomeClass *b = new(mem) SomeClass();
mem += sizeof(SomeClass);
SomeClass *c = new(mem) SomeClass();

, чтобы вы могли выделить всю память, а затем распределить ее по своему усмотрению. Примечание: убедитесь, что вы вызываете деконструкцию вручную, как это не происходит при вызове delete

-1
ответ дан 7 December 2019 в 10:05
поделиться

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

Каждой основной функции потока передается карта, содержащая зависимости (драйверы, почтовые ящики и т. Д.), И они сохраняются в классах, которые будут использовать их (вместо доступа к какой-то глобальной переменной).

Для каждой среды (цель, симулятор, модульный тест ...) вы создаете одну функцию "конфигурации", которая создает все необходимые объекты, драйверы и все потоки, предоставляя потокам их список зависимостей. Например, целевая конфигурация может создать драйвер USB и внедрить его в некоторый поток связи, в то время как конфигурация модульного теста связи может создать заглушку драйвера USB, которую контролируют тесты.

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

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

Примерно:

// Config specific to one target.
void configure_for_target_blah(System_config& cfg)
{   // create drivers
    cfg.drivers.push_back("USB", new USB_driver(...))
    // create threads
    Thread_cfg t;
    t.main = comms_main; // main function for that thread
    t.drivers += "USB"; // List of driver names to pass as dependencies
    cfg.threads += t;
}

// Main function for the comms thread.
void comms_main(Thread_config& cfg)
{
    USB_driver* usb = cfg.get_driver("USB");
    // check for null, then store it and use it...
}

// Same main for all configs.
int main()
{
    System_config& cfg;
    configure_for_target_blah(cfg);
    //for each cfg.drivers
    //    initialise driver
    //for each cfg.threads
    //    create_thread with the given main, and pass a Thread_config with dependencies
}
3
ответ дан 7 December 2019 в 10:05
поделиться
Другие вопросы по тегам:

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