Valgrind полезен для обнаружения затяжных ссылок на свободные объекты в куче. Тем не менее, похоже, что эта функция не содержит затянувшихся ссылок на переменные вне области видимости в стеке. Например:Как определить ссылки на переменные стека вне области видимости в C++?
#include <iostream>
struct CharHolder {
const char ch;
CharHolder(char _ch) : ch(_ch) {}
};
struct Printer {
const CharHolder& ref;
Printer(const CharHolder& _ref) : ref(_ref) {}
void print() {
std::cout << &ref << ": " << ref.ch << std::endl;
}
};
int main() {
// g++ -O0: prints 'x'
// g++ -O3: prints undefined character
Printer p1(CharHolder('x'));
p1.print();
// g++: prints undefined character
CharHolder* h = new CharHolder('x');
Printer p2(*h);
delete h;
p2.print();
}
В первом примере, с p1
, является тот, где принтер содержит ссылку на переменный стек вне области видимости, так как CharHolder('x')
разрушаются, как только строительство p1
завершено.
Второй пример, с p2
, это когда принтер содержит ссылку на переменную кучи, которая free'd перед тем p2
попытки ссылаться на него в print()
.
Valgrind жалуется на втором примере:
==82331== Invalid read of size 1
==82331== at 0x400A8E: Printer::print()
==82331== by 0x400967: main
==82331== Address 0x5a1c040 is 0 bytes inside a block of size 1 free'd
==82331== at 0x4C2C2BC: operator delete(void*)
==82331== by 0x40095F: main
Как можно обнаружить ошибки первого рода, возможно с помощью инструмента Valgrind?
'valgrind' не является инструментом статического анализа. – immibis
Я думаю, что это всего лишь урок предмета (каламбур), что неплохо хранить переданные ссылки любым способом, который сохраняется дольше, чем аргумент функции, в котором они передаются. Для любого вызова переданная ссылка может ссылаться на временный объект, и по возвращении он будет ссылаться на недопустимый объект, и тогда член будет бесполезен. Возможно, компиляторы должны быть созданы, чтобы генерировать предупреждение для такой ситуации. –
@BlairHoughton - Как вы предлагаете компилятору при компиляции вызова функции, который передает ссылку на временный параметр, может выяснить, что вызываемая функция хранит переданную ссылку где-нибудь, когда компилятор, возможно, никогда не компилировал исходный код вызываемой функции, в любой момент в известной записанной истории, так как время начала эоны назад? –