mavzermete 1
mavzermete
noisiv 1
noisiv
Manwe Work 1
Manwe Work
-Blaster- 2
-Blaster-
Hikaye Ekle

sectree.h for_each_entity() UB

C++:
template <class _Func> void for_each_entity(_Func & func)
{

    itertype(m_set_entity) it = m_set_entity.begin();

    for ( ; it != m_set_entity.end(); ++it) {

        LPENTITY entity = *it;

        // <Factor> Sanity check

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            m_set_entity.erase(it);

            continue;

        }

        func(entity);

    }
}

Bu kodda UB var;

it erase edilip continue statement yazılmış. erase(it) sadece silinen elemana ait iterator'ı invalidate eder, statementda loop invalidate edilmiş iteratörü increment ediyor, olması gereken "it = m_set_entity.erase(it)" yazıp for yerine while döngüsüne çevirmek (erase zaten bir sonraki geçerli iterator'ı döndürüyor). Neyse, biraz daha inceleyip özetle C++20 için şöyle bir çözüm üretebilirsiniz;

C++:
template <class _Func> void for_each_entity(_Func & func)
{
    std::erase_if(m_set_entity, [this](LPENTITY entity) {

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            return true;

        }

        return false;

    });

    std::ranges::for_each(m_set_entity, std::ref(func));

}

UB ise neden bugüne kadar patlamadı derseniz adı üstünde UB ne olacağını ancak Allah bilebilir, kimse öngöremez teknik detay için compiler dökümanlarına bakmak lazım.
 

En Çok Reaksiyon Alan Mesajlar

C++:
template <class _Func> void for_each_entity(_Func & func)
{

    itertype(m_set_entity) it = m_set_entity.begin();

    for ( ; it != m_set_entity.end(); ++it) {

        LPENTITY entity = *it;

        // <Factor> Sanity check

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            m_set_entity.erase(it);

            continue;

        }

        func(entity);

    }
}

Bu kodda UB var;

it erase edilip continue statement yazılmış. erase(it) sadece silinen elemana ait iterator'ı invalidate eder, statementda loop invalidate edilmiş iteratörü increment ediyor, olması gereken "it = m_set_entity.erase(it)" yazıp for yerine while döngüsüne çevirmek (erase zaten bir sonraki geçerli iterator'ı döndürüyor). Neyse, biraz daha inceleyip özetle C++20 için şöyle bir çözüm üretebilirsiniz;

C++:
template <class _Func> void for_each_entity(_Func & func)
{
    std::erase_if(m_set_entity, [this](LPENTITY entity) {

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            return true;

        }

        return false;

    });

    std::ranges::for_each(m_set_entity, std::ref(func));

}

UB ise neden bugüne kadar patlamadı derseniz adı üstünde UB ne olacağını ancak Allah bilebilir, kimse öngöremez teknik detay için compiler dökümanlarına bakmak lazım.
UB’nin bugüne kadar fark edilmemesinin asıl nedeni sanırım, yalnızca entity->GetSectree() != this tutarsızlığı oluştuğunda tetiklenmesidir. Normal InsertEntity/RemoveEntity akışı bu ilişkiyi tutarlı tuttuğundan sorunlu dal muhtemelen hiç veya çok nadir çalışıyor; çalıştığında da silinen düğümün belleği hemen bozulmadığı için kod şans eseri devam edebiliyor.

"UB ne olacağını ancak Allah bilebilir" cümlesi Necati ERGİN 'i hatırlatıyor. :)
Teşekkürler.
C++:
template <class _Func> void for_each_entity(_Func & func)
{

    itertype(m_set_entity) it = m_set_entity.begin();

    for ( ; it != m_set_entity.end(); ++it) {

        LPENTITY entity = *it;

        // <Factor> Sanity check

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            m_set_entity.erase(it);

            continue;

        }

        func(entity);

    }
}

Bu kodda UB var;

it erase edilip continue statement yazılmış. erase(it) sadece silinen elemana ait iterator'ı invalidate eder, statementda loop invalidate edilmiş iteratörü increment ediyor, olması gereken "it = m_set_entity.erase(it)" yazıp for yerine while döngüsüne çevirmek (erase zaten bir sonraki geçerli iterator'ı döndürüyor). Neyse, biraz daha inceleyip özetle C++20 için şöyle bir çözüm üretebilirsiniz;

C++:
template <class _Func> void for_each_entity(_Func & func)
{
    std::erase_if(m_set_entity, [this](LPENTITY entity) {

        if (entity->GetSectree() != this) {

            sys_err("<Factor> SECTREE-ENTITY relationship mismatch");

            return true;

        }

        return false;

    });

    std::ranges::for_each(m_set_entity, std::ref(func));

}

UB ise neden bugüne kadar patlamadı derseniz adı üstünde UB ne olacağını ancak Allah bilebilir, kimse öngöremez teknik detay için compiler dökümanlarına bakmak lazım.
UB’nin bugüne kadar fark edilmemesinin asıl nedeni sanırım, yalnızca entity->GetSectree() != this tutarsızlığı oluştuğunda tetiklenmesidir. Normal InsertEntity/RemoveEntity akışı bu ilişkiyi tutarlı tuttuğundan sorunlu dal muhtemelen hiç veya çok nadir çalışıyor; çalıştığında da silinen düğümün belleği hemen bozulmadığı için kod şans eseri devam edebiliyor.

"UB ne olacağını ancak Allah bilebilir" cümlesi Necati ERGİN 'i hatırlatıyor. :)
Teşekkürler.
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst