#c #address-sanitizer
Вопрос:
Почему следующий код
#include lt;iostreamgt; #include lt;vectorgt; typedef struct Number { int number = 15; } Number; int main() { std::vectorlt;Number*gt; nums(5); for (size_t i = 0; i lt; nums.size(); i) { Number num; nums[i] = amp;num; } std::cout lt;lt; nums[1]-gt;number lt;lt; "n"; return 0; }
триггер «AddressSanitizer: использование стека после области действия», но когда я комментирую строку 15: std::cout lt;lt; nums[5]-gt;number lt;lt; "n";
он хорошо компилируется? Как это исправить?
Команда компиляции: clang main.cpp -fsanitize=address,undefined -fno-sanitize-recover=all -std=c 17 -O2 -Wall -Werror -Wsign-compare -g -o debug_solution amp;amp; ./debug_solution
Комментарии:
1. Возьмите свой учебник по C и узнайте об
new
операторе. И примерноstd::shared_ptr
, пока ты этим занимаешься.2. Вы сохраняете в векторе адрес
num
: каков срок службыnum
?3. Не связано: В C вы определяете структуры как
struct Number { ... };
4. Примечание: Если вместо этого вы распечатаете адреса , в которых они хранятся
nums
, велика вероятность того, что вы обнаружите, что все они одинаковы. Должен дать вам несколько подсказок о том, что здесь пошло не так.5. Спасибо всем! Я на пути к тому, чтобы стать лордом c .
Ответ №1:
Проблема в том, что вы храните указатель на значение в стеке, которое выходит за рамки области видимости и уничтожается, оставляя висящий указатель.
std::vectorlt;Number*gt; nums(5); for (size_t i = 0; i lt; nums.size(); i) { Number num; nums[i] = amp;num; // num goes out of scope here and num[i] has a dangling pointer // to an invalid object } std::cout lt;lt; nums[1]-gt;number lt;lt; "n";
В этом игрушечном примере я вообще не вижу причин использовать указатели, и исправление состояло бы в том, чтобы просто использовать std::vectorlt;Numbergt;
:
std::vectorlt;Numbergt; nums(5); // per comment by @user4581301 // this loop is not really needed, as the constuctor will // default-construct the elements for you for (size_t i = 0; i lt; nums.size(); i) { Number num; nums[i] = num; } std::cout lt;lt; nums[1].number lt;lt; "n";
Если вам действительно нужно динамическое выделение памяти в куче, вам следует рассмотреть возможность использования std::vectorlt;std::unique_ptrlt;Numbergt;gt;
или std::vectorlt;std::shared_ptrlt;Numbergt;gt;
в зависимости от того, нужно ли совместно использовать объект между несколькими компонентами.
Комментарии:
1. В случае без указателей вообще нет необходимости в цикле.
std::vectorlt;Numbergt; nums(5);
созданы все необходимые значения по умолчаниюNumber
.2. Очень верно, добавлено примечание.
3. Большое спасибо! На самом деле это просто игрушечный пример, истинный код с той же проблемой составляет около 300 строк (идеальная реализация хэша).