구조체

서로 다른 형들의 집합으로 구성된 데이터를 의미한다. 배열은 이 중 특이한 경우인 것이다. 보통은 구조체보다는 클래스를 선호한다

구조체를 사용하는 예

데이터 관계를 이해하기 쉽게 하기 위해서 구조체를 사용한다

ex 오해의 소지가 있고 구조화되지 않은 변수를 사용한 VB 예제

name = inputname;

address = inputAddress;

phone = inputphone;

title = inputtile ;//...

ex 보다 많은 정보를 제공하고 구조화된 변수를 사용하는 VB 에제

employee.name = inputname;

employee.address = inputAddress;

employee.phone = inputphone;

employee.title = inputtile; //...

 

데이터 블록에 대한 작업은 단순화하기 위해서 구조체를 사용해라

매개변수 목록을 단순화시키기 위해서 구조체를 사용해라 - 구조체를 사용하여 루틴의 매개변수를 단순화할수 있다. 필요한 각각의 요소들을 개별적으로 전달하는 대신 연관된 요소들을 구조체로 묶은 다음, 구조체로 전체 내용을 전

달할수 있다.

ex 구조체를 사용하지 않고 서투른 방법으로 루틴을 호출하는 VB예제

HardWayRoutine { name, address, phone, ssn, gender, salary }

ex 구조체를 사용하여 세련된 방법으로 루틴을 호출하는 VB 예제

EasyWayRoutone { employee }

만약 numWithholdings를 추가하고 싶다면 HardWayRoutine 에 대한 호출을 모두 변경해주어야 한다. 하지만 employee 에 추가한다면 EasyWayRoutone 는 매개변수를 신경쓸 필요가 없다

유지보수를 줄이기 위해서 구조체를 사용해라 - 구조체를 사용하면 연관된 데이터를 그룹으로 묶기때문에 구조체를 변경할때 프로그램을 변경하는 경우가 적다.

 

포인터

포인터 사용은 현대적인 프로그래밍에서 오류를 유발할 가능성이 가장 높은 분야 중 하나이다. 그리고 자바와 C#, VB와 같은 현대적인 어너는 포인터 데이터형을 제공하지 않는다. 하지만 포인터를 잘 이해하면 프로그래밍 언어의

동작방식을 이해하는데 도움이 되고 여러가지 방어적인 프로그래밍 방법들에도 많은 도움이 된다.

포인터를 이해하는 패러다임

메모리상에서의 위치 - 메모리상에서의 위치는 주소이며 종종 16진수 표기법으로 표현된다. 포인터 자체는 이 주소만 포함한다. 포인터가 가르키고 있는 데이터를 사용하기 위해서는 해당주소로 가서 메모리의 내용을 해석해야 한다

메모리의 내용을 해석하는 방법 - 해당 포인터의 기본형에 의해서 제공된다. 정수를 가르키면 정수로, 문자열을 가르키면 문자열로 해석할수 있다.

포인터 사용의 팁

포인터 오류는 일반적으로 포인터가 절대로 가리켜서는 안되는 어딘가를 가르키기때문에 발생한다. 잘못된 어떤 값을 포인터 변수에 할당할때 써서는 안되는 메모리 영역에 데이터를 쓰게 된다. 이를 메모리 충돌(memory corruption) 이라 한다. 포인터의 성공적인 사용을 위해서 첫째, 처음부터 포인터 오류를 만들지 않는다. 둘재, 포인터 오류가 코드에 작성된 후 가능한한 빨리 발견되도록 한다.

  • 포인터 연산을 루틴이나 클래스로 고립시킨다.
  • 포인터를 선언과 동시에 정의해라.

        ex 잘못된 포인터 초기화 C++예

        Employee *employeePt;

        // 수 많은 코드

        employeePtr = new Employee();

       ex 포인터를 훌륭하게 초기화한 C++예

       //수 많은 코드

      Employee *employeePtr = new Employee();

  • 포인터를 할당된 곳과 같은 영역 내에서 삭제한다
  • 포인터를 사용하기 전에 검사한다
  • 포인터가 참조하는 변수를 사용하기 전에 검사한다
  • 손상된 메모리를 검사하기 위해서 도그태그(dog-tag)필드를 사용한다.
  • 명시적으로 중복하여 추가한다
  • 여분의 포인터 변수들을 사용한다ㅏ - 절대로 포인터 변수들을 아끼지 않는다. 변수는 하나 이상의 목적으로 사용되어서는 안된다.
  • 복잡한 포인터 표현식을 단순화해라
  • 그림을 그린다. - 포인터를 코드로 설명하면 혼란스러울수 있다. 일반적으로 그림을 그리는 것이 도움이 된다.
  • 연결 리스트에 있는 포인터들을 올바른 순서로 삭제한다
  • 임시메모리를 할당한다 - 만약 프로그램이 동적 메모리를 사용항다면, 갑자기 메모리 부족하게 되어 RAM공간에 있는 데이터를 잃게 되는 문제를 피해야 한다. 이러한 문제를 피하는 방법중에 하나가 임시메모리를 할당하는 것이다. 작업을 저장하기 위해서 얼마나 많은 메모리가 필요한지 결정한 다음, 작업을 정리한후 우아하게 프로그램을 종료시킨다. 즉 프로그램이 시작할때 메모리를 할당하고 남겨둔다. 그러면 프로그램에서 메모리가 부족하게 될 경우 임시 메모리를 해제한후 작업을 정리하고 종료한다
  • 쓰레기를 확실하게 제거해라.
  • 메모리를 삭제하거나 해제한 다음 포인터를 null로 설정한다.
  • 변수를 삭제하기 전에 잘못된 포인터를 검사한다
  • 포인터할당을 추적한다
  • 포인터문제를 피하기 위한 전략에 집중하기 위하여 커버(cover)루틴을 작성한다

 

C++ 포인터 포인터

  • 포인터와 참조의 차이점을 이해하라 - 포인터(*)와 참조(&) 모두 객체를 간접적으로 참조한다. 초보자입장에선 object->field와 object.field로 참조하는 외형 상의 차이가 있다. 하지만 가장 중요한 차이점은 참조가 항상 객체를 참조하는 반면에 퐁린터는 널을 가르킬수 있고 참조는 참조하는 대상이 초기화 된 후로 변경될수 없다
  • 참조로 전달 매개변수에 포인터를 사용하고 값으로 전달매개변수에 const참조를 사용해라 - 수정가능한 객체에서는 멤버에 대한 참조를  object->member표기법으로 사용할 것이며, 수정 가능하지 않은 객체에는 멤버에 대한 참조를 object.member표기법으로 사용할 것이다.
  • auto_ptrs를 사용해라 - auto_ptrs를 사용하는 습관을 들이도록 하자. auto_ptrs이 범위를 벗어날때 자동으로 메모리를 삭제함으로써, 일반적인 포인터와 관련된 많은 메모리 누수문제를 피할수 있다.
  • 스마트포인터(smart pointer)사용해라. - 스마트 포인터는 일반 포인터와 비슷하게 작동하지만 자원관리, 복사작업, 할당 연산, 객체 생성과 소멸등의 기능을 제공한다.

 

C - 포인터 포인터

  • 기본 형 대신 명시적인 포인터 형을 사용해라 ex NodePtr = (NODE_PTR) calloc (1, sizewof(NODE));
  • 형 변환을 피해라
  • 매개변수를 전달하고자 할때에는 별표규칙을 따른다.
  • 메모리 할당시 변수의 크기를 결정하기 위해서 sizeof()를 사용해라

 

전역데이터 -  어디서나 접근 가능한 데이터라 편리할수 있다. 그러나 숙달된 사람은 지양한다

전역 데이터를 사용할때 발생하는 일반적인 문제점

  • 전역 변수에 대한 부주의한 변경
  • 전역 데이터의 기괴하고 이상한 별칭 문제들
  • 전역 데이터의 재진입코드 문제 - 다중 thread일때 심각한 문제를 야기할수 있다.
  • 전역 데이터로 인한 코드 재사용문제 - 전역 데이터 변경은 원본 프로그램에 영향을 미칠뿐 아니라 오래된 클래스를 사용하는 모든 새로운 프로그램들에게도 영향을 미친다.
  • 전역 데이터와 관련된 불확실한 초기화 순서 문제점 - 서로 다른 번역 유닛사이에서 데이터가 초기화되는 순서가 어떤 언어 특히 C++에서는 정의되어 있지 않다.
  • 전역데이터로 인해 모듈화와 지적인 관리 용이서으이 손상

 

전역데이터를 사용하는 이유

  • 전역적인 값을 보관한다
  • 명명된 상수를 흉내내라
  • 열거형을 흉내내라
  • 매우 자주 사용되는 데이터에 대한 사용을 능률적으로 처리하라
  • 뜨내기 데이터(tramp data)를제거한다

최후의 수단으로만 전역데이터를 사용해라

  • 각 변수들을 로컬로 만든 다음, 필요할 때에만 변수를 전역으로 만든다 -  처음에는 지역변수로 만들고 필요할때 private와 protected로 전역을 선언한다
  • 전역 변수와 클래스 변수를 구분하라
  • 접근 루틴을 사용해라

 

전역데이터 대신 접근 루틴의 사용

전역데이터로 할수 있는 것은 접근 루틴으로 더 잘할수 있다. 접근 루틴의 사용은 추상데이터 형을 구현하고 정보 은닉을 이루기 위한 핵심기술이다.

접근 루틴의 장점

  • 데이터에 대한 제어를 집중시킬수 있다.
  • 변수에 대한 모든 참조가 보호되고 있음을 보증할수 있다
  • 자동으로 정보 은식이 갖는 일반적인 이점들을 얻게 된다.
  • 접근 루틴은 추상데이터형으로 변환하기 쉽다.

접근 루틴의 사용방법

  • 모든 코드가 접근 루틴을 통해서만 데이터에 접근할수 있도록 한다
  • 모든 전역 데이터를 한곳에 집어 넣지 않는다
  • 전역 변수에 대한 접근을 제어하기 위해서 잠금(locking)을 사용해라
  • 추상화 수준을 접근 루틴에 만든다
  • 데이터에 대한 모든 접근을 동일한 추상화 수준에서 유지한다

 

전역 데이터를 사용할때의 위험요소를 줄이는 방법

전역 변수를 분명히 하는 이름 규약을 만든다

모든 전역 변수에 주석을 잘 작성한 목록을 만든다

중간 결과를 포함하기 위해서 전역변수를 사용하지 않는다

전역데이터를 사용하지 않는 것처럼 가장하기 위해 모든 데이터를 거대한 객체에 입력하고 모든 것에 전달하는 방법을 사용하지 않는다

 

요점 정리

  1. 구조체는 프로그램을 덜 복잡하게 하고 이해하기 쉽게 만들며 유지 보수 하기 쉽게 만드는데 도움을 줄수 있다
  2. 구조체 사용을 고려할때마다 클래스가 더 좋은 방법인지 고려한다
  3. 포인터를 오류를 발생할 가능성이 있다. 접근 루틴이나 클래스, 그리고 방어적인 프로그래밍 습관을 사용하여 보호한다
  4. 전역변수를 사용하지 않는다
  5. 만약 전역변수를 꼭! 사용해야 한다면 접근 루틴을 통해서 처리한다. 접근 루틴은 전역 변수가 제공하는 것 이상을 제공한다

 

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2008. 1. 19. 15:54