2013-05-13 2 views
-1

개체의 크기와 배열입니다. 임시 개체를 만들었지 만 삭제하지 않으면 Valgrind는 메모리 누수와 오류를 표시합니다. 그것을 삭제하면 segfault가 발생합니다. 그냥 Valgrind의이 임시 개체를 삭제할 수 없습니다.

void Obj::resize() 
{ 
    Obj *temp = new Obj[size * 2]; //<-- line 92 
    for (int i = 0; i < size; i++) 
    temp[i] = objarray[i]; 
    delete [] objarray; 
    objarray = temp; 
    size *= 2; 
    //delete temp; //<-- causes segfault 
    //delete [] temp; // also segfaults, tried them both just in case :\ 
} 

가 여기에 Valgrind의 보고서입니다 ...에 대해 불평 궁금 : 나는 GDB 너무 좋은 아니에요

==9292== HEAP SUMMARY: 
==9292==  in use at exit: 21,484 bytes in 799 blocks 
==9292== total heap usage: 3,528 allocs, 2,729 frees, 91,789 bytes allocated 
==9292== 
==9292== 21,484 (2,644 direct, 18,840 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4 
==9292== at 0x4008409: operator new[](unsigned int) (vg_replace_malloc.c:357) 
==9292== by 0x804AC7E: MyClass::resize() (file.cpp:92) 
==9292== by 0x804AC34: MyClass::add(int, int) (file.cpp:82) 
==9292== by 0x804AAE6: getline(std::istream&, MyClass&) (file.cpp:66) 
==9292== by 0x8049772: main (otherfile.cpp:39) 
==9292== 
==9292== LEAK SUMMARY: 
==9292== definitely lost: 2,644 bytes in 1 blocks 
==9292== indirectly lost: 18,840 bytes in 798 blocks 
==9292==  possibly lost: 0 bytes in 0 blocks 
==9292== still reachable: 0 bytes in 0 blocks 
==9292==   suppressed: 0 bytes in 0 blocks 
==9292== 
==9292== For counts of detected and suppressed errors, rerun with: -v 
==9292== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 

만 가지고이 역 추적 :

(gdb) run 
Starting program: 

Program received signal SIGSEGV, Segmentation fault. 
0x46ed40e3 in free() from /lib/libc.so.6 
Missing separate debuginfos, use: debuginfo-install glibc-2.15-58.fc17.i686 libgcc-4.7.2-2.fc17.i686 libstdc++-4.7.2-2.fc17.i686 
(gdb) backtrace 
#0 0x46ed40e3 in free() from /lib/libc.so.6 
#1 0x4742dba0 in operator delete(void*)() from /lib/libstdc++.so.6 
#2 0x0804ad68 in MyClass::resize (this=0xbffff28c) at file.cpp:98 
#3 0x0804ac35 in MyClass::add (this=0xbffff28c, month=10, day=31) 
    at file.cpp:82 
#4 0x0804aae7 in getline (input=..., a=...) at file.cpp:66 
#5 0x08049773 in main (argc=1, argv=0xbffff344) at otherfile.cpp:39 
(gdb) 

포인터를 매달아 놓아야하기 때문에 이것을 삭제하는 것이 좋지 않다고 생각합니다. 그래서 제가 segfault를 얻는 것을 놀라게하지는 않습니다. 그럼에도 불구하고 왜 메모리 문제가 발생합니까? 어떤 아이디어라도 대단히 감사하겠습니다.

+4

왜 '임시'를 삭제 하시겠습니까? ** 당신은 **해서는 안됩니다. delete는 포인터를 해제하지 않지만 가리키는 포인터를 해제합니다. 'temp'를 지우면'objarray'도 삭제합니다. – stardust

+0

예, 알고 있습니다. 내가 왜 궁금해 하건데 아직도 메모리 문제를 일으키는 이유가 무엇입니까? – mcallinder

+0

segfault가 다른 원인에 의해 발생할 수 있습니다. 거기에 효과가 나타납니다. 하지만 원인은 추가 될 수 있습니다 ... – stardust

답변

1

실제로 나중에 objarray에 할당했기 때문에 삭제할 수 없습니다.

대부분의 경우 소멸자에서 objarray을 삭제하지 않을 것입니다. 또는 다른 함수가 이전 배열을 먼저 삭제하지 않고 다시 할당하는 것입니다.

나에게 할당 해제를 처리하기 위해 손으로 만들어진 배열보다는 std::vector을 사용할 것입니다. 이 두 번째 (또는 그 이상)이 resize를 호출 시간 인 경우

+0

고맙습니다. 당신 (그리고 다른 사람들)이 제안한 것처럼 나는 소멸자를 올바르게 활용하는 것을 게을리했다. – mcallinder

0

명시 적 delete (또는 delete[])은 매우 낮은 수준의 라이브러리 코드에서만 필요합니다. 다른 곳에서는 스마트 포인터를 사용해야합니다.

가 여기에있는 더 나은 접근 방식 (IMO) 쉽게 이해하기 : 그것 뿐이다

std::unique_ptr<Obj[]> temp(new Obj[size * 2]); 

// copy stuff from objarray to temp 

swap(objarray, temp); 

합니다. 스왑이 성공하면 unique_ptr 소멸자는 이전 objarray 버퍼를 해제합니다. 그리고 복사 중에 예외가 발생하면 새로운 임시 버퍼가 해제됩니다. 어느 경우 든 objarray (역시 std::unique_ptr<Obj[]>이어야 함)에는 유효한 버퍼가 남아 있습니다.

+0

'std :: unique_ptr'의 사용은 아마도 여기에서 가장 간단한 해결책 일 것입니다,하지만 저는' 스왑 '이 작동합니다. 'swap'의 두 인자 모두 같은 타입을 가져야합니다. (일반적으로, 물론 : 그는 기본적으로'std :: vector'를 다시 구현하고 있습니다. 그리고 일반적인 경우에 올바르게 수행합니다. 예를 들어,'Obj'가 기본 생성을 지원하지 않는다면, 그다지 중요하지 않습니다.) –

+0

@James : 당연히'objarray' 또한'unique_ptr '이어야합니다 ... 원시 포인터가 될 이유는 없습니다. –

+0

@Sarien : 포인터를 바꿔 넣을뿐입니다. 이제'temp'는 파괴 될 필요가있는 오래된 버퍼를 소유하고,'resize'의 닫는 중괄호에서 범위를 벗어나면 그렇게합니다. –

0

은, 다음이 당신이 temp가 이미 삭제 된 이후 이미 double delete을했다 힙에 delete에 노력하고 있기 때문에, 매우 가능성 시나리오, 그리고 지금 모든 objArray 기록은 코드가 아닌 힙 관리에 속한 많은 메모리에 저장됩니다.

메모리가 다른 일부 개체에 사용 중이며 objArray로 사용하는 힙 메모리에 내용을 쓰는 것과 같은 여러 가지 잠재적 문제가 발생할 수 있습니다.

temp을 삭제하려고 시도하면 안됩니다. 그냥 하지마.