Макрос после выполнения кода в течение срока программы


Я использую этот маленький макрос много:

#define RUN_ONCE(runcode) \
{ \
    static bool code_ran = 0; \
    if(!code_ran){ \ 
        code_ran = 1; \
        runcode; \
    } \
}

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

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



3605
11
задан 27 августа 2011 в 12:08 Источник Поделиться
Комментарии
4 ответа

Он не является потокобезопасным. Вы можете использовать импульс, или стандарта C++11 и std::call_once.

Ответ на комментарий:

Boost и с++11 это определение включает библиотеки для запуска потоков и синхронизации потоков (блокировки, атомарные переменные...). В call_once функция может либо использовать те, чтобы гарантировать потокобезопасность или использовать нить Либ ОС (компиляции под *Nix).

Очень упрощенный (unefficent) реализация может быть:

static std::mutex mutex;
static bool called = false;
{
std::lock_guard<std::mutex> lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}

Это не очень эффективно, потому что замок всегда берут. Оптимизации его атомарно проверить некогда флаг, прежде чем принимать мьютекс:

static std::mutex mutex;
static std::atomic<bool> called = false;
{
if (!called) {
std::lock_guard<std::mutex> lock(mutex);
if (!called) {
f(); // <- User code
called = true;
}
}
}

Реализация pthread_once в glibc интересно: это гораздо сложнее, так как он старается вести себя правильно в присутствии вилки.

Повышение/в C++11 использовать функтор (указатель на функцию или объект с оператором()): таким образом он может быть реализован как функция, а не макрос (можно использовать лямбда-выражения в C++11, Чтобы не определить отдельную функцию).

16
ответ дан 27 августа 2011 в 12:08 Источник Поделиться

Обратите внимание, что макросы, такие как это должно быть помещено в Сделать { ... }, а (0) блока, в противном случае вы столкнетесь с проблемами, когда макрос вызывается до другого, т. е.

#define RUN_ONCE(runcode) \
do \
{ \
static bool code_ran = 0; \
if (!code_ran) \
{ \
code_ran = 1; \
runcode; \
} \
} while (0)

например, если вы столкнулись с такой ситуацией:

if (do_foo)
RUN_ONCE(foo());
else
printf("do_foo is false\n");

без У ... А (0) это будет расширяться:

if (do_foo)
{
static bool code_ran = 0;
if (!code_ran)
{
code_ran = 1;
foo();
}
}; // <<< syntax error here !
else
printf("do_foo is false\n");

Но с помощью сделать ... а (0) мы получаем:

if (do_foo)
do
{
static bool code_ran = 0;
if (!code_ran)
{
code_ran = 1;
foo;
}
} while (0); // <<< no syntax error here !
else
printf("do_foo is false\n");

12
ответ дан 30 августа 2011 в 07:08 Источник Поделиться

Почему вы ставите код, который определяет правильное использование функции внешние функции.

Вместо этого почему бы не поместить код внутри функции, то она никогда не может быть неправильно использована.
Главным приоритетом является сохранение и повторное использование. Вы должны написать код таким образом, что она не может быть неправильно использована.

Таким образом, а не:

#define RUN_ONCE(runcode) \
{ \
static bool code_ran = 0; \
if(!code_ran){ \
code_ran = 1; \
runcode; \
} \
}

void init_random()
{
srand(time(NULL));
}

int main()
{
RUN_ONCE(init_random())
}

Вы можете сделать это:

void init_random()
{
static bool code_ran = 0;
if(!code_ran)
{
code_ran = 1;
srand(time(NULL));
}
}

int main()
{
init_random();
}

3
ответ дан 27 августа 2011 в 06:08 Источник Поделиться

Макросы, как правило, плохой выбор, потому что какой-то сумасшедший дерново всегда найдет плохое способ, чтобы использовать их...

RUN_ONCE(}else{ or_not();)

1
ответ дан 8 сентября 2011 в 01:09 Источник Поделиться