C++: почему работает этот простой Scope Guard?

До сих пор у каждого взгляда на защиту области действия была логическая переменная защиты. Например, см. это обсуждение: самый простой и аккуратный c++11 ScopeGuard

Но простой сторож работает (gcc 4.9, clang 3.6.0):

template <class C>
struct finally_t : public C {
    finally_t(C&& c): C(c) {}
    ~finally_t() { (*this)(); }
};
template <class C>
static finally_t<C> finally_create(C&& c) {
    return std::forward<C>(c);
}
#define FINCAT_(a, b) a ## b
#define FINCAT(a, b) FINCAT_(a, b)
#define FINALLY(...) auto FINCAT(FINALY_, __LINE__) = \
    finally_create([=](){ __VA_ARGS__ })

int main() {
    int a = 1;
    FINALLY( std::cout << "hello" << a << std::endl ; );
    FINALLY( std::cout << "world" << a << std::endl ; );
    return 0;
}

Почему временные копии не уничтожаются? Опасно ли полагаться на такое поведение?


person funny_falcon    schedule 10.08.2015    source источник
comment
Вы наблюдаете эффекты Copy Elision (или Move Elision, в данном случае). Copy Elision не гарантируется/обязательна, но обычно выполняется основными компиляторами даже при компиляции без оптимизации. Попробуйте -fno-elide-constructors от gcc, чтобы увидеть, как он ломается: melpon.org/wandbox/permlink/B73EuYYKGYFMnJtR   -  person dyp    schedule 10.08.2015
comment
Есть хитрость, позволяющая не полагаться на удаление копии, требуется несколько изменений. Вот модификация вашей версии, не основанная на исключении копии.   -  person Evgeny Panasyuk    schedule 15.10.2015


Ответы (1)


Вы наблюдаете эффекты Copy Elision (или Move Elision, в данном случае). Copy Elision не гарантируется/не является обязательным, но обычно выполняется основными компиляторами даже при компиляции без оптимизаций. Попробуйте gcc -fno-elide-constructors, чтобы увидеть, как он «сломается»: http://melpon.org/wandbox/permlink/B73EuYYKGYFMnJtR

person Community    schedule 23.11.2015