Следующая минималистичная программа дает сбой при компиляции с -O3
и, возможно, с -O2
, но нормально выполняется с -O0
(с clang 4.0):
#include <iostream>
class A {
public:
virtual void me() const { std::cerr << "hi!\n"; }
};
class B {
public:
B(const A& a_) : a(a_) {}
virtual void me() const { a.me(); }
private:
const A& a;
};
class C {
public:
C(const B& b_) : b(b_) {}
void me() const { b.me(); }
public:
const B& b;
};
int main() {
C c = C(A());
c.me();
}
Причина в том, что c.b
инициализируется ссылкой на временный объект класса B
, созданный из временного A
. После выхода из конструктора c.C()
временный B
исчезает, но ссылка на него остается в c.b
.
Какие хорошие методы я могу использовать, чтобы избежать этой ситуации, учитывая, что я не контролирую реализацию B
или A
? Существуют ли статические анализаторы, способные обнаруживать это состояние? (Моя версия scan-build
не обнаружила проблемы.)
-fsanitize=undefined,address
компилятору и компоновщику. ASan и UBSan должен уведомлять вас во время выполнения. - person nwp   schedule 15.09.2017C c = C(&A());
, вы заслужили сбой. Мне просто не нравятся классы со ссылками на члены, они затрудняют перемещение и копирование. - person rodrigo   schedule 15.09.2017-fsanitize-address-use-after-scope
надежно обнаруживает ошибку в моей системе. - person krlmlr   schedule 15.09.2017