Chapter 4. Compound Types

지환·2022년 6월 5일
0
책에서 좀 세세하게 설명하다보니 한 개념을 여러군데로 나눠서 이거배우고 자세히 설명하고 이런 식이네.
난 정리목적이니 책과는 순서가 좀 다를 수 있음.

array, pointer, structure, ... 등의 compound type 알아보자(class도 compound type이긴한데 얘는 나중에)

Array 같이 다른 type들로부터 만들어지는 type을 "Compound Type"이라고 한다.
C에서는 derived type이라고 하는데, C++에선 이 용어를 class에서 사용하므로 다르게 말하는 것이다.

Arrays

memory에 연속적으로 저장

array size는 integer constant여야 한다. 프로그램이 running하는 동안에 set되는 변수는 안된다.
ex. 10, const variable, 1*2, 8*sizeof(int), 등등
(얘는 const가 그냥 쓰이게 해주네)

Initialization Rules

배열 크기보다 작게 initialize하면 남은 공간은 0으로 초기화
long cake[5] = {0}; -> set all elements zero

int num_elements = sizeof(things) / sizeof(short); -> 배열 길이 계산 가능

마찬가지로 C++11부터 = 기호 없어도 작동
double height[3] {185.3, 174.7}; -> C++11 이후로 허용

empty braces를 사용해 0으로 set할 수 있다.
float height[3] = {};
float height[3] {}; -> 위에랑 둘 다 0으로 set된다.
이 기호를 쓰면 (다들 그렇듯) assignment시 narrowing이 안된다.

STL에서 기본 array type보다 좀 더 정교한 vector template class나 array template class를 정의한다.

Strings

C++에선 두가지 방법으로 string을 다룬다.
1. C-style string
2. string class library

C-style string

array 길이 더 길면 나머지는 null character로 초기화됨.
당연한 것이, 배열 뒤 나머지는 0으로 초기화되는데 그게 null character(ascii code 0)임.

string constant와 character constant는 엄연히 다르다.
'S'는 숫자 83을 나타내지만, "S"'S''\0'으로 이루어져있다.
심지어 "S"는 memory address를 나타낸다.
string literal은 수정 불가능하니 const char * name = "john"; 식으로 pointer에 const를 같이 사용해 assign할 수 있다.(배열은 굳이 const 안붙이지 않나.. 뭐 용도맞게 잘 쓰면 되겠지)

string이 white space(spaces, tabs, newlines)로만 구분되면 자동으로 합쳐짐
"abc" "def" == "abcdef"
합쳐질때 띄어쓰기 같은거 안 더해지고, 첫번째 string의 '\0' 위치에 두번째 string의 첫번째 문자가 바로 따라온다.

C-style String Input : cin

아래와 같이 cin을 이용해 문자열을 입력받을 수 있다.

const int Size = 15;
char name[Size];

cin >> name;

keyboard에서 null character를 입력할 수 없으므로, cin은 white space로 end of string을 판별
그리고 그 white space는 input queue에 놔둔다.

cin으로 입력받으려면 할당된 공간이어야한다. 즉, new로 할당받은 포인터이거나, 배열 이름이거나.
cin은 배열 크기 넘어서는 문자열이 들어왔을때 protection 기능이 없다.(Ch 17에서 더 논의)

C-style String Input : Line at a Time

istream class에 (위처럼 white space로 구분되는 단어 단위로 입력받는게 아니라) line단위로 입력받을 수 있는 getline(), get() 함수가 있다.
즉, new line character로 구분된다.

getline()
: newline character는 discard
cin.getline(strAry, length); 형식으로 사용
strAry는 input 문자열이 저장될 배열이고, length는 input 문자열의 최대 길이
(길이를 20으로 명시하면 최대 19개만 입력 받는다. because of '\0')

get()
: newline charcter를 input queue에 그대로 놔둠
위처럼 cin.get(strAry, length); 형식으로 인자 두개 넘겨주는 같은 형식으로 사용된다.
혹은 cin.get(); 이렇게 인자없이 사용하면 다음 character 하나만 읽고 버린다.
newline character를 input queue에 남겨두는게 문제가 될 수 있는데, 이를 cin.get();으로 해결

cin.get(strAry, length).get(); 으로도 사용할 수 있다.
cin.get(strAry, length)cin object를 반환하기 때문에 가능하다.
cin.getline(name1, ArSize).getline(name2, ArsSize); -> 얘도 가능
(cin >> year).get(); -> 얘도 가능

함수가 여러 형태, 어떤건 인자가 2개고 어떤건 없어도 되고, 로 쓰일 수 있는 것은
function overloading 덕분이다.
C에선 이런게 불가능했지만.. 같은 이름의 함수를 argument list를 보고서 구별해 적용한다.

get()을 쓰는 이유??
1. older implementation은 getline()이 없다.
2. get()을 통해 문자열을 다 읽었는지, 중간에 끊겼는지 알 수 있다. 다음 input queue에 남은 것을 확인해 newline character인지 보면 된다.
newline 이라면 그 line을 다 읽은 것이고, 아니라면 길이 제한때문에 중간에 끊긴 것..
즉, getline은 사용하기 편하고, get은 error체크하기 편하다.

Empty input??
get()failbit라는 것을 설정하고, 다음 input을 막는다. cin.clear();로 input을 재개할 수 있다.
더 긴 input??
getline()이 failbit를 설정하고 다음 input을 막는다.
둘 다 남은 input은 그대로 input queue에 놔둔다.

C-style string etc

cout << chary << "abc"; (chary는 char 배열)
cout엔 문자열의 주소를 넘겨서 출력한다. (C도 printf 첫번째 인자에 문자열 배열 이름 와도 됐었음)
C++에서(C와 마찬가지로) "abc" 같은 string constant는 <첫번째 element의 주소>를 나타낸다.

문자열 포인터 주소 cout으로 출력하려면 int*로 cast해줘야한다. char*을 그냥 넣으면 문자열로 인식하기 때문이다.

이런 C-style detail은 `std::string` object를 사용해서 피해갈 수 있다.
assignment도 그냥 할 수 있고 그럼...

String Class

std namespace에 포함됨
string header를 include해야 사용할 수 있다.

string object를 사용해 string을 저장한다.
class definition은 문자열 특성을 user로부터 숨기므로, string을 그냥 일반 변수처럼 사용할 수 있다.

아래 예시를 통해 사용법 보자.

#include <string>

int main() {
	using namespace std;
    
    string str1;
    string str2 = "hello world";  //C-style string으로 초기화 가능
    
    cin >> str1;       //cin 가능, 이때 str1의 size는 자동으로 늘어난다.
    cout << str1;      //cout 가능
    cout << str2[2];   //array notation 사용해서 개별 character 접근 가능
}

size 자동 조절

여기선 string을 char가 여러개 있는 array of char에 저장된다고 보기보단, 단일 entity로 간주해야한다.
C-style string과 다르게 마지막을 null character로 저장하지는 않는다.(p.227)

Initialization, Assignment, Concatenation, Appending, StringLength

Initialization
C++11
char date[] = {"abc"};
string date = {"abc"};
이렇게 list-initialization도 가능
(위에 말했듯이 그냥 string literal로 초기화 할 수도 있다.)

Assignment
array에선 assignment가 불가능했으나, string object끼리는 assign 가능
str1 = str2;

Concatenation
+ operator를 이용해 두 string obejct 합칠 수 있다: str3 = str1 + str2;
+= operator도 가능: str1 += str2;

String Length
size() class method 사용
str2.size();
str2는 string object

string class가 생기기 이전)

cstring header를 사용해 C언어 string 기능 사용했다.
assign대신 복사하기위해 strcpy 함수, concatenate하려고 strcat 함수 사용 (안전성때문에 strncpystrncat 사용하기도 함)
string 길이는 strlen() 함수 사용

character array와 string object를 "초기화 하지 않았을때" 문자열 길이 연산을 하면 다른 결과가 나온다.
strlen을 적용하면 null character까지 길이를 계산하므로 문자열 길이가 0이 안나올 수도 있다.
하지만 size를 적용하려면 string object여야하는데, 얘는 자동으로 size조절이된다.
초기화하지 않았다면 자동으로 0으로 size 조절이돼서, size() 함수를 적용하면 0이 잘 나온다.

추가 string Class I/O

cin이나 cout 가능

string object도 line 단위로 입력 받으려면?
getline(cin, str); : cin이 argument로 들어오고, length specifier는 X

dot notation이 없다. == 이 getline은 class method가 아니다.
cin에서 input을 찾도록 알려주는 것이다.

또 length specifier가 없는건, string object는 자동으로 resizing 할 수 있기 때문

왜 getline 사용법이 다른가?(왜 string쓸땐 getline이 istream class method가 아닌가?)
: istream class가 string class 만들어지기 이전부터 있었기 때문에
istream class method가 다른 type은 지원하지만 string type에 대해 지원하지 않는 것이다.
그래서 string object들은 클래스 method가 아닌 일반 함수 사용한다.
operator>>()도 string에대해서는 사실 일반 함수를 쓰고,
getline도 마찬가지인건데 cin에선 티가 안날뿐인거지

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
그럼 왜 string object에 cin이 적용되지?
: 다음 code에서 x가 basic C++ type이라면
`cin >> x;`
얘는 내부적으로 istream class의 member function을 사용한다. (disguised notation)이라고 하네
string에 대해서도 disguised notation으로 string class의 friend function을 사용하는 것이다.
(나중에 자세히 알게될거니 일단은 string에 대해 cin, cout은 잘 된다고 알고있으면 됨.)

String Literals (다른 form)

(아래는 이미 배운 것들)

char name[] = "John";
wchar_t name[] = L"John";
char16_t name[] = u"John";
char32_t name[] = U"John";

이것 말고도 UTF-8에 따라 character가 저장되도록 할 수 있다.
string literal에 u8 prefix를 사용

raw string이란 것도 있는데, escape sequence를 인정하지않고 문자 그대로 저장된다.
즉, \n을 저장해도 newline character가 아니라 backslash와 문자 n으로 해석된다. 엔터키를 쳐서 입력하면 carriage return character로 들어간다.
"(, )"를 delimiters로 사용하고, R prefix를 사용한다.
R prefix는 다른 prefix와 combine돼 사용할 수 있다. ex) Ru를 붙여서 char16_t에 raw string 저장 가능

raw string에서 일반 string처럼 " 를 delimiter로 사용하면 raw string내에서 " 를 쓰지 못한다.
그래서 "( 를 delimiter로 사용하는데, 그럼 "( 를 쓰고싶으면?
: " 와 ( 사이에 다른 문자를 넣어서 delimiter로 사용할 수 있다. (대신 둘은 짝이 맞아야함)
"+*( 와 )+*" 를 delimiter로 짝이맞게 사용하면 문제 해결 가능(뭐 다르게 delimiter 써도 되고)

Strucutres

struct person {
	char name[20];
    int age;
    bool sex;
};
person Mark;

C와 다르게, structure tag를 쓸때 앞에 struct를 안붙여도 된다.

tag는 없어도 된다. 대신 tag나 typedef 안쓸거면 바로 변수선언 따라와줘야 의미있음.

. : membership operator 라고 함.
(class member functions에 접근하기 위해 썼던 .이 이렇게 structure member 접근하는 것에서 기원했다.)

structure내에 string Class member를 사용할 수 있다.(지원만 한다면)

Initialization

struct abc {
	int a;
    int b;
} ex1 = {1, 2};

C++11부터 =은 optional
abc ex1 {1, 2};도 가능
그리고 계속 말하지만, {} 이렇게 비워두면 모두 0으로 set되고, narrowing은 당연 안된다.

추가로, C++ structure는 멤버 변수 말고도 member function을 가질 수도 있다.(잘 쓰이진 않음)
Ch10에서 보자.

Bit Fields (in Strucutres)

register와 대응되는 data structure를 만들기에 좋다.
field type은 integral or enumeration type 이어야만 한다.
unnamed fields가 spacing을 위해 쓰일 수 있다.


Unions

C++에선 structure에서처럼 tag"만"으로 사용될 수 있다.

anonymous union : tag나 해당 type의 변수 선언 없이 union을 선언하는 것이다.
ex)

union {
	int a;
    long b;
};

이러면 같은 address를 공유하는 ab 변수가 만들어진다.
특별한 표현법 없이 그냥 ab로 사용할 수 있다.

union은 대부분(무조건은 아니고) 공간을 절약하기 위해 사용한다.
요즘은 RAM이 기가바이트단위라 크게 필요가 없을 수도 있지만,
여전히 임베디드 시스템 등에선 공간 절약이 중요하다.

Enumerations

symbolic constant를 만드는 const 외에 또 다른 방법
보통 이 목적으로 더 많이 쓴다.
enum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};
이렇게 아무 이름 없이 하면 enum type 변수 선언 없이 쉽게 constants만 사용 가능

enum spectrum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};
spectrum을 enumeration, red, yellow 등을 enumerator라고 한다.
이 경우 각 enumerator는 순서대로 integer values 0-7을 갖는다.

Enumeration type Operation
1) enumeration type에 enumerator만 assign 가능
2) enumerator -> integer type으로 필요할때 자동 변환됨
이 둘만 가능하다고 보면 된다.
(1 경우는 implementation따라 다르지만 portability를 위해 이 둘만 사용하는게 good)

spectrum band;
++band;

이런게 implementation따라 가능하기도 하지만, maximum portability를 위해 그냥 최대 제한 사항으로 한다.

ex)
enumerator는 integer type으로 바뀌지만, int는 자동으로 enumerator로 바뀌지 않는다.
color = 3 + red; : valid
(enumeration엔 addition이 정의되지 않았지만, 이 경우는 int로 변환되기 때문에 가능한 것)

band = orange + red; : invalid
orange + red는 int로 바껴서 연산이 되지만 band에 int를 assign할 수 없으므로 불가능

band = spectrum(3); : 이렇게 type casting 해주면 valid

Value Ranges (for Enumerations)

enum value range안에 들어가는 숫자라면 enumerator와 일치하지 않는 숫자이더라도 type casting 통해서 assign 될 수 있다.

value range를 정하는 원리는 일단 가장 큰 값을 찾고, 그 값을 포함할 수 있는 2의 거듭제곱 수를 찾는다. 그리고 그 수에서 1을 빼면 range의 upper end가 나온다.
lower end는 최솟값이 0이상이라면 0이다. 하지만 음수라면, 위와 같은 원리로 찾는다.(마지막에 더하기 1)

예를들어, enum bigstep{fisrt, second = 100, third};의 range는 0~127이다.
bigstep a = bigstep(50); 이런식으로 range 안의 숫자면 casting 통해서 assign할 수 있는 것이다.


Pointers and the Free Store

데이터를 저장하기위해? "(1)어디에 (2)어떤크기를 (3)어떤값을" 이 세가지 정보를 유지해야함.
간단한 변수 선언(compile-time) 말고, pointer를 이용(run-time)해보자.

& operator는 C나 C++이나 주소 연산에 쓰인다.
단, C++에선 reference variables을 표현할때도 &를 쓴다.
OOP는 compile-time이 아닌 run-time에 결정내리는 것을 강조하는데,
이것이 OOP와 기존 procedural programming의 차이점이다.
runtime decisions은 현재 상황에 맞게 조정할 수 있도록 flexibility를 제공한다.
예를 들자면 미리 array를 선언해두기보다 필요에 맞게 공간을 할당받아 쓰는 것이다.
new keyword 등을 이용하면 가능하다.
(C도 이 정도는 가능하긴한데,
OOP에서 이 부분을 강조한다고하니 뭐 나중에 다른 runtime decision 기능도 알려주겠지)

Declare
주소만 저장하는게 아니라 어떤 type을 가리키는지도 알아야하므로 type 명시해야함.(dereference할때도 필요하고하니)

int * p1, p2; : 주의, p1은 pointer이고 p2는 그냥 int임.

C++에서 int *은 compound type이다. pointer-to-int

array처럼 pointer도 그냥 pointer가 아니라 기본 type에 기반한 type이다.
double* 과 int* 은 다른 type
(둘이 다른 type이긴하지만 주소의 길이는 자체는 같기때문에, sizeof 적용해보면 크기는 같다.)
(computer system마다 주소 길이 자체는 다를 수 있다. 여기선 4byte, 저기선 2byte)

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
0은 null pointer를 의미
C에서 처럼 표면적으로 0이고 실제 저장되는 값은 상요할 수 없는 주소이거나 이런건가보다.
나중에 자세히 알려주겠지

Pointer Danger

pointer를 만들면, address를 hold하기위한 공간은 allocate되지만, 그 address가 가리키는 공간은 할당되지 않는다.

long * fellow;
*fellow = 223323;

그래서 이런 식의 code는 매우 좋지 않다.
만약 fellow가 가리키는 공간이 program code가 있는 공간이라면? 쉽지 않다.
pointer에 dereferencing operator 적용 전에 항상 명확하고 적당한 주소로 initialize 해야한다.

그렇다고 그냥 integer assignment 불가능
int * pt = 0xB8000000; : type mismatch (C99 이후로도 불가)
int * pt = (int *) 0xB8000000; : OK

혹은 new를 이용해 memory를 할당 받을 수도 있다.

new

variable은 compiletime에 할당된 named memory
pointer를 이용해 runtime에 할당된 unnamed memory를 사용할 수 있다.

named memory는 variable이라고 하고, unnamed memory는 data object라고 한다.
(여기서 말하는 object란 OOP에서의 object가 아니라, data item이 있는 할당된 memory block을 의미한다. variable을 포괄하는 개념)
compiletime, runtime에 할당됐다는 것의 의미?

C : malloc function (C++도 사용가능)
C++ : new operator

typeName * pointer_name = new typeName;
int * ptr = new int; (type name 사용)
new가 해당 크기의 memory를 찾아서 address 반환
memory를 할당할 수 없으면 exception을 throw한다.

variable은 memory 영역 중 stack 부분을 사용하지만,
new를 통해 할당받은 memory는 heap(free store) 영역이다.
그래서 함수 반환시 자동으로 해제되는 variable과 다르게, new를 통해 할당받은 영역은 따로 해제해줄 필요도 있다.
(어셈블리어 생각해보면 함수 반환될때 stack frame pointer 다시 복구 시키는 과정에 당연히 남은 영역들은 deallocate됐다. 다시 한번 상기)
메모리 영역
메모리 영역 여기 그림도 괜춘하네

delete

delete operator

int * ptr = new int;
delete ptr;

이렇게 해제(free)하면 해당 공간이 해제되는 것이지, ptr은 다른 주소를 가리키든지해서 계속 사용할 수 있다.

new로 할당된 "공간"만 해제할 수 있다. 변수로 할당된 공간은 해제할 수 없다.
new로 할당된 주소이기만 하면 된다. 다른 포인터이더라도 같은 new로 할당된 주소 가리키고있으면 OK
해제한 주소를 또 해제하는건 undefined

null pointer에도 delete하는게 안전하다고 하네

new와 delete는 같은 곳을 가리키기만하면 다른 함수에서 해도 상관없지만,
까먹을 수 있기때문에 "되도록 같은 함수에서 할당/해제를 해주는게 좋다."
C++ classes는 constructors와 destructors를 이용해 이를 관리한다.

new와 Dynamic Arrays

compile-time에 선언하는걸 static binding이라고하고, run-time에 선언하는걸 dynamic binding이라고 한다.

typeName * pointer_name = new typeName [num_elements];
int * ary = new int [10];

delete 문법 좀 다름 : delete [] ary;
(element 하나가 아니라 배열 전체를 해제하라고 알려주는 것)

pointer는 시작 주소만 가리키므로 배열 개수는 내가 따로 저장해야한다.
program이 delete 같은 연산 하기위해 elements 개수를 keep track하긴하지만, 그 정보가 항상 사용 가능하진 않기 때문이다.
sizeof 연산을 new로 할당된 메모리에 적용해도 byte가 정확하게 나오지 않는다.왜?

memory에서 어떤 크기의 byte만큼을 값으로 읽을지는 pointer type이 정하는 것
malloc에서도 할당받는 크기는 따로고, 읽어오는 단위는 당연히 해당 pointer 기준이었다.

new와 Dynamic Structures

class가 structure와 유사하므로 이 section의 기능들은 class에도 똑같이 적용할 수 있다.

node * ptr = new node; : node는 structure type이라 가정 (java instance 생성하는거랑 비슷하게 생겼네)
접근 방법은 알다싶이.. ptr->value = 3; (ptr은 해당 memory의 이름이 아니므로)
혹은 (*ptr).value = 3;


Pointers, Arrays, Pointer Arithmetic

배열 이름은 대부분 첫번째 element의 address로 해석되고, ary[i]*(ary+i)로 해석된다.
(포인터에서 덧셈뺄셈은 type에 맞는 크기로 알아서 계산됨. 4byte type이면 +1하면 +4가 됨.)

ary는 array name이여도 되고 pointer variable이여도 저렇게 해석됨.

배열 이름이 주소로 "해석될 수 있다."는 것이다. 항상 주소인 것은 아니다.
포인터와 달리 다른 곳을 가리킬 수도 없다.

Tip.
string 입력받을때 일단은 엄청 큰 배열에 받고,
그 다음 그에 맞는 크기 할당 받아서 저장하는 함수
(좋은 아이디어인 것 같아 적어둠.. p.181)

Automatic Storage, Static Storage, Dynamic Storage

Thread storage도 있다.(C++11, Ch9)
data object의 수명을 기준으로 나눔

Automatic Storage

block 시작될때 ~ 끝날때까지 exist
block내에서 define된 변수로 automatic variable이라고 불린다.

Static Storage

전체 프로그램 진행되는동안 exist
1) 함수 밖에서 define하거나
2) static keyword와 함께 define

K&R C에선 static array와 structure만 initialization이 가능했다.
C++Release2.0이나 ANSI C 이후론 automatic array/structure도 초기화 가능

Dynamic Storage

static이나 automatic variable이 있는 공간과 다른 공간인 heap(free store)이란 공간을 이용한다.
new, delete

메모리를 더 자유롭게 control 할 수 있지만, 새로운 메모리 공간을 할당하는건 좀 더 어렵다.(automatic variable은 stack에서 그냥 다음 memory로 쌓아버리면 되니까)

memory leak
new로 특정 공간을 할당받고, ptr이 그곳을 가리키고 있었는데, 해당 공간을 delete하기전에 ptr의 lieftime이 끝나면?
그런 경우를 우리는 memory leak 이라 한다.
심각한 경우 메모리 다 잡아먹힌다.
Even the best programmers and software companies create memory leaks.
그래서 new와 delete는 바로바로 짝지어두는 습관을 갖는게 좋다.
(C++의 smart pointer가 이 작업의 자동화 도움)

memory fragmentation : leak이랑은 다르게, 재할당 반복하면서 작은 구멍들이 계속 생기는 것


Combinations of Types

구조체의 배열, 구조체 포인터의 배열 등 다양한 형태 가능

이런 좀 복잡한 type을 선언할때 auto가 유용하다.

struct antarctica_years_end {
	int year;
    //추가 data
};

...
antarctica_years+end s01, s02, s03;

const antarctica_years_end ** ppa = arp;  //이런 복잡한건 auto로 선언 가능
auto ppb = arp;
std::cout << (*ppa)->year << std::endl;  //이렇게 접근

Array Alternatives

vector & array template classes -> built-in array의 대안
여기서 일단 간단하게만..

The vector Template Class

dynamic array를 사용한다는 점에서 string class와 비슷
vector object를 runtime동안 set할 수 있고, 중간이나 끝에 새 데이터 삽입 가능
(내부적으로 new와 delete를 자동으로 알아서 쓰며 resizing.)

1) include vector header file
2) vector identifier는 std namespace이므로, using declaration쓰든지 아니면 std::vector로 쓰든지 하면 된다.
선언 방법은 아래와 같음

#include <vector>
using namespace std;

vector<int> vi;        //길이 0인 int형 array
vector<double> vd(n);  //길이 n인 double형 array

vector<typename> vt(n_elem) ;
: n_eleminteger constant이거나 integer variable

The array Template Class (C++11)

vector는 편하긴한데 built-in array에 비해 효율성을 좀 떨어진다. <- dynamic storage파트에서 stack보다 heap에 저장하기가 좀 더 어렵다(?)했는데 그 얘기인듯
그래서 fixed-size array는 그냥 built-in array를 쓰는데, 또 이 경우엔 안전성과 편리성이 좀 떨어진다.
그래~서! fixed-size이면서 stack공간(혹은 static memory allocation)을 사용하는 array template class를 만들었다.
heap 공간을 사용하지 않아서 효율성을 높이고, 안전성도 추가했다.
std namespace이다.

#include <array>
using namespace std;

array<int, 5> ai;
array<double, 4> ad = {12, 2.1, 3.43, 4.3};

array<typename, n_elem> vt ;
: n_eleminteger constant이어야한다. integer variable 불가 (당연히 const 변수는 가능하다. C++에선 그게 constant expression이니까(ch3). 예시 p.355)

C++11 이후로 vector, template object에 list-initialization이 가능하다.
C++98땐 vector object는 list-initialization 불가능했었다.
(지금은 C++11로 많이전환됐을라나..? 안됐다고하면 뭐 후자 방식 잘 인지하고 있어야지)

built-in arrays VS vector Objects VS array Object

셋 다 elements에 접근하는 방식은 기존 array와 같다. ary[1]

built-in array와 array object는 같은 영역(stack)에 저장되고, vector object는 다른 영역(heap, free store)에 저장된다.
"그래서" 전자 두개는 배열 크기에 integer constant가 와야하고, 후자의 경우 배열 크기에 integer variable이 오는 것도 허용한다.
("그래서" 라는 말이 맞는진 모르겠지만, 뭐 위 이유때문에 이런거지않을까)

array object끼리는 크기만 같으면 서로 assign할 수 있다.
(built-in array는 assign하고싶으면 하나씩 했어야됨)

built-in array는 배열 크기 넘어가도 a[i] == *(a+i)로 취급하고 따로 범위 넘었는지 check는 안하므로 unsafe

array obejct나 vector object도 a[i]식으로 쓰면 boundary check 안되는건 마찬가지이다.
하지만, at() member function을 이용하면 boundary check가 되고, 범위 넘어가면 abort
ary.at(2) = 3; ([] 이거 대신 사용하는 격)
(대신 at() 사용하면 run time이 증가함, 그래서 이 함수가 강제가 아니라 option인 것이다.)

begin(), end() 같은 다른 추가 멤버함수는 Ch16에서...

영단어

blemish 흠
conceal 감추다
tedious 지루한
ungracious 불친절한
veil 면사포
gobble 게걸스럽게 먹다
disguise 변장하다
derived 파생된
accentuate 강조하다
contiguous 인접한
weave 엮다
delimit 범위를 정하다

0개의 댓글