clang-tidy: deadcode.DeadStores nie rozumie RAII?

0

Przyznam szczerze, że nie wiem jak dokładnie działa clang-tidy. Natrafiłęm na taki false-positive:

#include <functional>
#include <iostream>
 
class OnExit
{
public:
    OnExit(const std::function<void()>& f):f_(f){}
    ~OnExit(){f_();}
private:
    std::function<void()> f_;
};
 
void finish(const bool& details)
{
    std::cout << "foo finished with " << std::boolalpha << details << std::endl;
}
 
int foo(int i)
{
    bool details = false;
    OnExit action{std::bind(&finish, std::cref(details))};
    if (i < 0)
    {
        throw 0;
    }
 
    if (i < 10)
    {
        return i;
    }
    int result = i*6;
 
    details = true;
 
    if (i < 100)
    {
        return result + 5;
    }
 
    details = false;
    return result*result;
}
 
int main()
{
    std::cout << foo(5) << std::endl;
    std::cout << foo(20) << std::endl;
    try
    {
        std::cout << foo(-1) << std::endl;
    }
    catch (...)
    {
        std::cout << "exception" << std::endl;
    }
    std::cout << foo(120) << std::endl;
}

W skrócie:

  • OnExit to narzędzie RAII mające za zadanie wywoływać przekazaną funkcję przy wyjściu ze scope'u. C++ implementacja scope guardów znanych z D.
  • chcemy przy zakończeniu działania funkcji foo() wywołać funkcję finish i wyprintować aktualną wartość zmiennej boolowskiej 'details'. Dlatego tworzymy na stosie guarda, bindujemy do niego funkcję finish z const referencją na 'details' jako parametr
  • clang-tidy twierdzi, że zmienna details nigdy nie jest używana:
2 warnings generated.
<<path>>/neverused.cpp:33:5: warning: Value stored to 'details' is never read [clang-analyzer-deadcode.DeadStores]
    details = true;
    ^
<<path>>/neverused.cpp:33:5: note: Value stored to 'details' is never read
    details = true;
    ^
<<path>>/neverused.cpp:40:5: warning: Value stored to 'details' is never read [clang-analyzer-deadcode.DeadStores]
    details = false;
    ^
<<path>>/neverused.cpp:40:5: note: Value stored to 'details' is never read
    details = false;
    ^

Ktoś ma wiedzę, czy to raczej powszechny problem clang-tidy, czy raczej coś specyficznego, co warto drążyć, zgłosić im? Zawsze mogę to zsupresować w idiomatyczny sposób:

(void)details;

( https://clang-analyzer.llvm.org/faq.html#dead_store ) i mieć to gdzieś, ale wolałbym się dowiedzieć.

1

Zamień:

OnExit action{std::bind(&finish, std::cref(details))};

Na:

OnExit action{[&details]{ finish(details); }};

Wnioski już sam wyciągniesz. IMHO chyba chcesz mieć:

explicit OnExit(std::function<void()>&& f): f_{f} { }
0
Mokrowski napisał(a):

Zamień:

OnExit action{std::bind(&finish, std::cref(details))};

Na:

OnExit action{[&details]{ finish(details); }};

Wnioski już sam wyciągniesz.
Oczywiście, że z lambdą działa. Może postaram się zmienić pytanie: co takiego robi reference_wrapper, że clang-tidy nie jest w stanie ogarnąć, że wykorzystujemy zmienną details?

Mokrowski napisał(a):

IMHO chyba chcesz mieć:

explicit OnExit(std::function<void()>&& f): f_{f} { }

Jasne, w oryginalnym kodzie był explicit

1 użytkowników online, w tym zalogowanych: 0, gości: 1