Valgrind сообщает об утечке памяти при назначении значения строке

Valgrind сообщает об утечке памяти при назначении значения строке.

Я использовал следующий простой код для проверки утечки памяти, сообщенной Valgrind.

/******************************************
* FILE: t3.c
* Compiled using : g++ -g t3.c -o t3
*
* $ g++ -v
* Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.6/specs
* Configured with: ./configure --prefix=/usr --infodir=/share/info --mandir=/share/man
*      --enable-languages=c,c++ --with-system-zlib --program-suffix=-3.4 --enable-threads=posix
* Thread model: posix
* gcc version 3.4.6
 ******************************************/


#include <iostream>
#include <string>

using namespace std;

/**************************************************************
 **************************************************************/
int main(int argc, char *argv[])
{
   string test = "XXXXXXXXX";
   cout << "this is a test " << test << endl;
   exit(0);
}

Я скомпилирую эту команду:

$ g++ -g t3.c -o t3

И когда я запускаю Valgrind, он сообщает об утечке памяти, когда я пытаюсь присвоить значение строке. Я использую этот простой тест для исследования утечки памяти в реальной программе, и кажется, что использование строки может вызвать какую-то проблему.

В 0x8048A6F: main (t3.c: 23) - строка: string test = "XXXXXXXXX"; Может кто-нибудь дать некоторый намек на такое странное поведение?

[[email protected] C]$   valgrind --leak-check=full  ./t3
==3910== Memcheck, a memory error detector.
==3910== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==3910== Using LibVEX rev 1732, a library for dynamic binary translation.
==3910== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==3910== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==3910== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==3910== For more details, rerun with: -v
==3910==
this is a test XXXXXXXXX
==3910==
==3910== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 25 from 1)
==3910== malloc/free: in use at exit: 102 bytes in 3 blocks.
==3910== malloc/free: 4 allocs, 1 frees, 126 bytes allocated.
==3910== For counts of detected errors, rerun with: -v
==3910== searching for pointers to 3 not-freed blocks.
==3910== checked 194,136 bytes.
==3910==
==3910== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==3910==    at 0x4017846: malloc (m_replacemalloc/vg_replace_malloc.c:149)
==3910==    by 0x4018E05: realloc (m_replacemalloc/vg_replace_malloc.c:306)
==3910==    by 0x41B441A: argz_append (in /lib/libc-2.2.5.so)
==3910==    by 0x41593B9: __newlocale (in /lib/libc-2.2.5.so)
==3910==    by 0x40E010B: std::locale::facet::_S_create_c_locale(__locale_struct*&, char const*, __locale_struct*) (c++locale.cc:99)
==3910==    by 0x407EF6F: std::locale::facet::_S_initialize_once() (../../.././libstdc++-v3/src/locale.cc:172)
==3910==    by 0x407EFB4: std::locale::facet::_S_get_c_locale() (../../.././libstdc++-v3/src/locale.cc:185)
==3910==    by 0x407A422: std::ctype<char>::ctype(unsigned short const*, bool, unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/i686-pc-linux-gnu/bits/ctype_noninline.h:104)
==3910==    by 0x40801D5: std::locale::_Impl::_Impl(unsigned) (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92)
==3910==    by 0x4080EED: std::locale::_S_initialize_once() (/usr3/BUILD/gcc/gcc-3.4.6/libstdc++-v3/libsupc++/new:92)
==3910==    by 0x4080F84: std::locale::_S_initialize() (../../.././libstdc++-v3/src/locale_init.cc:155)
==3910==    by 0x4080FE7: std::locale::locale() (../../.././libstdc++-v3/src/locale_init.cc:102)
==3910==
==3910==
==3910== 22 bytes in 1 blocks are possibly lost in loss record 2 of 3
==3910==    at 0x4017C38: operator new(unsigned) (m_replacemalloc/vg_replace_malloc.c:163)
==3910==    by 0x40BF2C4: std::string::_Rep::_S_create(unsigned, unsigned, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:81)
==3910==    by 0x40C1CE4: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:150)
==3910==    by 0x40C1E15: std::string::string(char const*, std::allocator<char> const&) (/usr3/BUILD/gcc/gcc-3.4.6/i686-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1386)
==3910==    **by 0x8048A6F: main (t3.c:23)**
==3910==
==3910== LEAK SUMMARY:
==3910==    definitely lost: 16 bytes in 1 blocks.
==3910==      **possibly lost: 22 bytes in 1 blocks.**
==3910==    still reachable: 64 bytes in 1 blocks.
==3910==         suppressed: 0 bytes in 0 blocks.
==3910== Reachable blocks (those to which a pointer was found) are not shown.
==3910== To see them, rerun with: --leak-check=full --show-reachable=yes
[[email protected] C]$

Ответ 1

Потому что вы вызываете exit(0), поэтому деструктор строки никогда не вызывается. Просто используйте return 0.

Для разработки конструктор std::string выделяет кучную память для хранения строки, полагаясь на деструктор, чтобы освободить эту память. Если вы объявляете строковый объект в стеке, деструктор будет автоматически вызываться, когда объект строки выходит из области видимости, освобождая память. Но exit - действительно механизм C; он немедленно выходит из программы без выполнения разворачивания стека, что означает, что деструкторы С++ для локальных объектов стека не будут вызываться.

Ответ 2

Если вы выделяете пять строк, вы получаете пять раз утечку памяти, или это все равно такая же сумма? Если это такая же сумма, то у вас, вероятно, нет утечки вообще. Некоторые библиотеки выделяют память для внутренней бухгалтерии/эффективности/и так далее, которая не освобождается, пока после того, как valgrind перестанет смотреть. Они становятся воспринятыми как утечка памяти, потому что ваша программа вызвала выделение, но никогда не вызывала освобождение. Если это в пять раз больше суммы, то ваша реализация строки может быть виновата. Я согласен с Чарльзом Сальвией, хотя... попробуйте еще раз с return 0; вместо exit(0); и посмотрим, что это изменит.

Ответ 3

В одном из моих классов компьютерных наук нам сказали, что Valgrind выводит информацию о строках, о которых нам не следует беспокоиться. Здесь файл подавления, который они нам дали для строк: https://sites.google.com/site/complingfiles/files/string.supp

Ответ 4

Несмотря на отсутствие exit(0) в конце программы, у меня была аналогичная проблема с ложными срабатываниями с std::string. Я статически связывался с libstdc++. Переключение ссылок на общий доступ и компиляция с помощью GLIBCXX_FORCE_NEW подавляло предупреждения.