sliver__

[Mastering C++ Programming] - Issues with raw pointers 본문

CS/C++

[Mastering C++ Programming] - Issues with raw pointers

sliver__ 2022. 12. 7. 16:25
728x90
  • 복잡한 데이터 구조와 알고리즘은 포인터를 요구하는 경향이 있습니다. 
  • raw pointers는 문제가 생길 때까지 작업하기에 정말 좋습니다.
  • raw pointers는 사용하기 전에 메모리와 함께 할당되어야 하며 완료되면 할당 해제가 필요합니다. 그렇게 간단합니다. 
  • 그러나 포인터 할당이 한 곳에서 발생하고 할당 해제가 또 다른 곳에서 발생할 수 있는 제품에서는 상황이 복잡해집니다. 
  • 메모리 관리 결정이 올바르게 이루어지지 않으면 사람들은 메모리를 확보하는 것이 호출자 또는 호출 수신자의 책임이라고 생각할 수 있으며 때때로 메모리가 어느 곳에서도 해제되지 않을 수 있습니다. 
  • 또 다른 가능성은 동일한 포인터가 다른 위치에서 여러 번 삭제되어 application crash로 이어질 수 있다는 것입니다. 
  • Windows 장치 드라이버에서 이런 일이 발생하면 파란 화면이 표시될 가능성이 큽니다.

  • 애플리케이션 예외가 있고 예외를 던진 함수에 예외가 발생하기 전에 메모리에 할당된 많은 포인터가 있는 경우를 상상해 보십시오. 누구나 추측할 수 있습니다. 메모리 누수가 있을 것입니다.
  • 예제 코드는 아래와 같습니다.
#include <iostream>
using namespace std;

class MyClass {
      public:
           void someMethod() {

                int *ptr = new int();
                *ptr = 100;
                int result = *ptr / 0;  //division by zero error expected
                delete ptr;

           }
};

int main ( ) {

    MyClass objMyClass;
    objMyClass.someMethod();

    return 0;

}
  • 결과는 아래와 같습니다.
g++ RawPointer.cpp -std=c++17
RawPointer.cpp:10:35: warning: division by zero is undefined [-Wdivision-by-zero]
                int result = *ptr / 0;  //division by zero error expected
  • Linux는 오작동하는 불량 애플리케이션을 찾는 데 매우 영리하며 나머지 애플리케이션이나 OS에 피해를 주기 전에 적시에 제거합니다. 
  • 코어 덤프는 실제로 좋지만 Linux 접근 방식을 축하하는 대신 저주를 받습니다. Microsoft의 Windows 운영 체제도 똑같이 더 똑똑합니다.
  • fishy memory 액세스를 수행하는 일부 응용 프로그램을 발견하면 버그 검사를 수행하고 Windows OS는 Linux OS의 코어 덤프와 동일한 미니 덤프 및 전체 덤프를 지원합니다.
  • 메모리 누수 문제를 확인하기 위해 Valgrind 도구 출력을 예제는 아래와 같습니다.
valgrind --leak-check=full --show-leak-kinds=all ./a.out

==32857== Memcheck, a memory error detector
==32857== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==32857== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==32857== Command: ./a.out
==32857== 
==32857== 
==32857== Process terminating with default action of signal 8 (SIGFPE)
==32857== Integer divide by zero at address 0x802D82B86
==32857== at 0x10896A: MyClass::someMethod() (main.cpp:12)
==32857== by 0x1088C2: main (main.cpp:24)
==32857== 
==32857== HEAP SUMMARY:
==32857== in use at exit: 4 bytes in 1 blocks
==32857== total heap usage: 2 allocs, 1 frees, 72,708 bytes allocated
==32857== 
==32857== 4 bytes in 1 blocks are still reachable in loss record 1 of 1
==32857== at 0x4C2E19F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32857== by 0x108951: MyClass::someMethod() (main.cpp:8)
==32857== by 0x1088C2: main (main.cpp:24)
==32857== 
==32857== LEAK SUMMARY:
==32857== definitely lost: 0 bytes in 0 blocks
==32857== indirectly lost: 0 bytes in 0 blocks
==32857== possibly lost: 0 bytes in 0 blocks
==32857== still reachable: 4 bytes in 1 blocks
==32857== suppressed: 0 bytes in 0 blocks
==32857== 
==32857== For counts of detected and suppressed errors, rerun with: -v
==32857== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[1] 32857 floating point exception (core dumped) valgrind --leak-check=full --show-leak-kinds=all ./a.out

 

  • 이전 raw pointer에 할당된 메모리는 포인터가 가리키는 메모리가 스택 해제 프로세스 중에 해제되지 않으므로 해제되지 않습니다.
  • 함수에 의해 예외가 발생하고 동일한 함수에 의해 예외가 처리되지 않을 때마다 스택 해제가 보장됩니다. 
  • 그러나 포인터가 가리키는 메모리가 아닌 스택 해제 프로세스 중에 자동 로컬 변수만 정리됩니다. 
  • 이로 인해 메모리 누수가 발생합니다.

  • 이것은 raw pointer 사용으로 인한 이상한 문제 중 하나입니다. 
  • raw pointer를 사용하는데 대가가 따릅니다. 
  • 그러나 이 문제를 처리하기 위해 C++에서 사용할 수 있는 좋은 대안이 있기 때문에 지불된 패널티는 그만한 가치가 없습니다. 
  • 스마트 포인터를 사용하는 것이 raw pointer에 추가되는 비용을 지불하지 않고 포인터를 사용하는 이점을 제공하는 솔루션입니다.

  • 따라서 스마트 포인터는 C++에서 포인터를 안전하게 사용하는 방법입니다.
728x90
Comments