갓똥
나는야 프로그래머
갓똥
전체 방문자
오늘
어제
  • 분류 전체보기 (186)
    • 프로그래밍 (146)
      • 자바 (9)
      • 안드로이드 (2)
      • 유니티 (20)
      • C++ (38)
      • C# (56)
      • HTML (2)
      • 파이썬 (3)
      • 자료구조 (2)
      • 알고리즘 (0)
      • 문제풀이 (4)
      • 디자인 패턴 (7)
      • 카카오톡 봇 (1)
      • 엑셀 (1)
      • 기타 (1)
    • 게임 (21)
      • 테일즈위버 (0)
      • 카이로소프트 (1)
      • 순위 (19)
      • 기타 (1)
    • 일상 (13)
      • 카페 (1)
      • 방탈출 (12)
    • 기타 (6)
      • 웃긴자료 (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

태그

  • 강남 방탈출
  • c# delegate
  • 전세계 게임 매출
  • c# unboxing
  • c# 코루틴
  • 유니티 골드그래프
  • 전세계게임매출순위
  • 유니티 그래프
  • 게임매출순위
  • C# 예외 처리
  • c# coroutine
  • pc 게임 순위
  • 자바
  • C++ 상속
  • Unity Graph
  • 글로벌게임매출
  • C++ 소멸자
  • C++
  • 2020년 게임 매출
  • 롤 골드그래프
  • 게임 매출 순위
  • pc게임 순위
  • 유니티 그래프 그리기
  • 모바일 게임 순위
  • 게임 디자인 패턴
  • C++ virtual
  • c# Thread
  • c# collection
  • C# boxing
  • 알고리즘

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
갓똥

나는야 프로그래머

[C++] 동적 메모리 할당, nullptr
프로그래밍/C++

[C++] 동적 메모리 할당, nullptr

2019. 10. 27. 20:52
728x90
반응형

1. 동적 메모리 할당

#include <cstdlib>

int main() {
    int* p1 = (int*)malloc(sizeof(int)*10);
    
    free(p1); 
    // C언어에서의 메모리 할당
    
    int* p2 = new int; // int 한 개, 4byte
    
    delete p2;
    // C++에서의 메모리 할당
    
    int* p3 = new int[10];
    delete[] p3;
    
    int* p4 = new int[10][2];
    delete[] p4;
}

  - C언어

    => malloc으로 할당하고 free로 해지한다.

    => C언어에서는 캐스팅이 필요 없지만, C++에서 malloc사용시 반환되는 주소는 원하는 포인터 타입으로 캐스팅 해야 한다.

 

  - C++

    => new로 할당하고 delete로 해지한다.

    => new가 반환한 주소를 캐스팅 할 필요 없다.

    => 배열의 형태로 할당한 경우는 delete[]로 해지 해야한다.

    => 배열을 delete[]가 아닌 delete로 해지하면 어떻게 될까? - C++표준문서에 delete[]를 안쓸경우에 대한 내용이 없음 -> 컴파일러마다 다른 오류를 배출할 것(미정의 동작, undefined)

 

  - malloc은 생성자는 호출하지 못하지만 new는 생성자를 호출한다.

 


2. nullptr

int main() {
    int* p1 = 0;
    int* p2 = nullptr;
}

  - C++11부터 도입된 새로운 키워드

  - 널 포인터 값(null pointer value)을 나타내는 포인터 리터럴(pointer literal)

  - 포인터 변수를 초기화 하기 위해 기존의 방식대로 0을 사용해도 되지만 nullptr을 사용하는 것이 안전하고 코드의 가독성을 높일 수 있다.

 

2.1 0의 특징

#include <iostream>

void move(int    n) { std::cout << "int"    << std::endl; }
void move(double d) { std::cout << "double" << std::endl; }
void move(bool   b) { std::cout << "bool"   << std::endl; }
void move(char*  s) { std::cout << "char*"  << std::endl; }

int main() {
    int    n = 0;
    double d = 0;
    bool   b = 0;
    char*  s = 0;
    
    move(0); // ? - int
    move(0.0); // 실수 리터럴
    move(false); // bool 리터럴
    move((char*)0); // char*, 포인터 리터럴
    move(nullptr);  // char*, 포인터 리터럴
}

  - 0은 정수, 실수, bool, 포인터 등의 변수를 초기화 할 때 사용 가능

 

위에서 0은 정수, 실수, bool, 포인터를 초기화 하고 있고, 위에 move함수는 파라미터가 다르므로 4개를 만들었다.
이 때, move(0); 으로 함수를 호출하면 무엇이 호출될까? 

  - 0은 정수형 literal이고 int 타입

    => 0은 int타입이지만, 실수, bool, 포인터 타입으로 암시적 형 변환될 수 있다.

 

그럼 int타입을 인자로 받는 move함수를 주석처리 해버린다면 move(0);은 어떤 함수를 호출할까?

  - 컴파일 시간에 함수호출 타입이 모호하다고 에러가 난다.

 

  - 리터럴(literal)

    => 소스 코드 내에서 사용되는 고정된 값

    => 변수 초기화나 구문 등에서 많이 사용된다.

    => 모든 리터럴은 데이터 타입이 있다.

literal 값 종류 데이터 타입
0 정수형 literal int
0.0 실수형 literal double
false boolean literal bool
nullptr pointer literal ?

  - nullptr의 데이터 타입은 뭘까?

 

2.2 nullptr과 코드 가독성

int* move() { return 0; }

int main() {
    auto ret = move();
    
    // if(ret==0) { }
    if(ret==nullptr) { }
}
위의 코드는 move()함수를 호출하고 반환값을 auto로 받아 ret의 타입을 결정하고 ret이 0이라면 무언가를 하겠다란 코드이다.
당신이 이 코드를 작성해놓았는데 다른사람이 이 코드를 본다고 생각해보자. 
다른 사람 입장에선 move함수를 보기 전까진 0이라고 조사를 하고 있기 때문에 ret이 int, double, bool, pointer인지 모른다.
따라서 0이 아닌 nullptr일 경우 다른 사람이 보기에도 pointer타입인것을 바로 알 수 있다.

  - 0을 사용하는 것보다 nullptr을 사용하는 것이 코드 가독성이 좋다.

 

2.3 nullptr과 데이터 타입

int main() {
    0;        // int
    0.0;      // double
    nullptr;  // std::nullptr_t
    
    int*  p1 = nullptr;
    char* p2 = nullptr;
    void(*f)() = nullptr;
    
    int n1 = nullptr; // error
    int n2 = 0;
    
    bool b1 = nullptr; // error
    bool b2(nullptr); // ok - 직접 초기화
    bool b3{nullptr}; // ok - 일관된 초기화
    bool b4 = {nullptr}; // error - 복사 초기화
}

  - nullptr은 std::nullptr_t 타입

  - std::nullptr_t 타입은 모든 타입의 포인터로 암시적 변환 된다.

  - std::nullptr_t 타입은 int타입으로 변환 될 수 없다.

  - std:nullptr_t 타입은 bool타입으로 직접 초기화(ditrect initialization)시 초기값으로 사용이 가능하다.

 

2.4 NULL과 nullptr

#include <iostream>

void move(int   n) { std::cout << "int"   << std::endl; }
void move(void* p) { std::cout << "void*" << std::endl; }

void idle(char* n) { std::cout << "idle" << std:: endl; }

/*
#ifdef __cplusplus
    #define NULL 0
#else
    #define NULL (void*)0
#endif
*/

int main() {
    move(0); // int
    move((void*)0); // void*
    move(NULL); // int
    
    idle(NULL); // ok
}

  - C와 C++의 차이점

      C       void* -> 다른 타입* / 암시적 변환 허용
    C++     void* -> 다른 타입* / 암시적 변환 불가
__cplusplus - 모든 C++컴파일러는 이 매크로가 정의되어 있다.

  - NULL

    => C/C++에 따라 구현 방법이 다르다.

    => 컴파일러의 종류, 버전에 따라서도 구현 방법이 다르다.

    => 일반적으로 C++ 컴파일러는 정수 리터럴 0으로 정의 하는 경우가 많다.

 

!! 포인터 변수를 초기화 하거나 값을 조사 할 때는 0 또는 NULL을 사용하지 말고, nullptr을 사용하자.

728x90
반응형

'프로그래밍 > C++' 카테고리의 다른 글

[C++] 객체지향 프로그래밍의 개념(2)  (0) 2019.10.29
[C++] 객체지향 프로그래밍의 개념(1)  (0) 2019.10.29
[C++] Explicit Casting  (0) 2019.10.25
[C++] 레퍼런스(reference)  (0) 2019.10.22
[C++] range for / if init / if constexpr  (0) 2019.10.18
    '프로그래밍/C++' 카테고리의 다른 글
    • [C++] 객체지향 프로그래밍의 개념(2)
    • [C++] 객체지향 프로그래밍의 개념(1)
    • [C++] Explicit Casting
    • [C++] 레퍼런스(reference)
    갓똥
    갓똥
    공부하며 알아가는 내용을 정리해 봅니다.

    티스토리툴바