-
Notifications
You must be signed in to change notification settings - Fork 10
/
0357.txt
448 lines (448 loc) · 20.6 KB
/
0357.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
예 안녕하세요 포프입니다
최근 들어 이제 C++ 강의 자료를 만들고 있는데
만들다가 이제..
저는 학생들한테 코딩 스탠다드를 강제할 거거든요
일단은 사회에 나올 때
어느 정도 코딩 스탠다드가 되고
어느 정도 깔끔한 코드를 짤 수 있으면
당연히 남들보다 훨씬 잘해 보이기 때문에
코딩 스탠다드를 이제 얘기하다가..
그니까, 이제 강제하려고 생각하다 보니까
몇 가지 코딩 스탠다드를
설명할 일이 있더라고요 강의자료에서
그래서
그 중에 나온 게
오늘 얘기할 건데
앞으로 몇 가지 코딩 스탠다드에 대해서
얘기를 할 것 같아요
왜 이 코딩 스탠다드를 내가 쓰고,
왜 이게 좋은 아이디어인지
첫 번째는 이제 C++에만 한정되는 얘기에요
그..
C++에 보면은 reference라는 게 나왔잖아요
참조라 그런 거 같죠? 이.. 펭귄 모양 & 이거 쓰는 거
ampersand라고 하는 거
그리고 C++이 나오기 전에 예전에는 당연히
포인터가 있었고, ' * '
그리고 이제..
인터뷰 문제이기도 한데 사실은 이게
인터뷰 보는 애들한테, C++ 한다는 애들한테 물어봐요
"야 포인터하고 레퍼런스가 있는데, 니가 컴파일하면은
어셈블리어에 차이가 있을까?" 이런 질문을 해요
거기서 대답을 못 하는 애들은 포인터가 어떻게 도는지도
감을 못 잡고 있는 애들이고
레퍼런스가 왜 나온지도 고민 안 해 본 애들이고
거기서 답을 할 수 있는 애들은
그때 고민해서 했든 아니면 그 전에 고민해서 했든
어디서 들었든 이제 그 대답을 아는 친구들이고
그래서 결과적으로 얘기하면은
어셈블리어는 똑같아요
한 마디로 얘기해서,
C에 없는 게 다른 언어에서 나왔다
그러면은 그거는 그 언어에서 추가한 기능이고
그 언어에서 뭐 컴파일러가 이상한 짓을 하든
런타임이 이상한 짓을 하든
그 기능을 컴퓨터가 이해할 수 있는 기능으로
바꿔 준다고 생각하면 돼요
컴파일러가 해 주면 그나마 효율적이겠고
자바 같이 비효율적인 언어에서는
비효율적이겠고 당연히
그런 거죠
레퍼런스는 어떻게 보면 이제 포인터의 문제점을
고치기 위해 나온 거라고 보면 맞거든요
그럼 이제..
포인터의 문제점이 뭐냐
포인터는 아무 address나 가리킬 수 있는 그런 변수니까
이 address를 잘못 넣는 순간,
내가 소유하지 않은 메모리에 쓰거나
엉뚱한 데 써 갖고 프로그램이 뻑이 난다거나
이상한 짓이 나올 수 있어요
의도하지 않게 버그가 그런 경우가 있을 수가 있죠
그래서 포인터 쓰는 게 되게 위험한 경우도 있죠
근데 포인터를 쓰면은 효율성..
포인터를 써서 가져오는 성능 향상도 엄청나기 때문에
그거를 단순히 무시할 수도 없고요
그래서 이거를 아마 고칠려고 했던 언어 중의 하나가
아마 자바였던 것 같아요
아무래도 C++을 만지기 너무 힘들어하는 그런 프로그래머들?
그거 해서 너무 실수를 많이 만드는 프로그래머들
솔직히 많거든요?
근데 그 사람들이
"이런 거 걱정 안 하고 빨리 코딩을 할 수 있게 만들자"
"제품을 빨리 만들 수 있게 만들자"라는 게
거기서 나왔던 게 아마
자바 쪽 계열이었던 것 같고
원래 목적은 다른 거였다고 하지만
어쨌든 그랬고
거기서 얘네들이 한 건 뭐냐면
포인터라는 거를 없앴다고 생각을 하죠
근데 포인터를 없앤 게 아니라
모든 오브젝트를 포인터로 만든 거죠 사실은
그니까 재밌는 게 뭐냐면
이게 포인터가 아니라면은
만약에
함수에 오브젝트를 건네줄 때, 자바에서, 그 오브젝트가
값으로 복사해 가야 되죠 정상적이라고 하면은
그러면 함수 안에서 그 값을 바꾸더라도
함수 밖의 값은 안 바뀌어야 돼요
근데 자바에서 오브젝트를 매개변수로 전달해 주면은
그건 사실은 그 레퍼런스를 전달해 준 거에요
정확히 얘기하면은 포인터를 전달해 준 게 전부에요
오브젝트가 있고, 이 오브젝트를 가리키는 주소를
그 함수에 전달해 준 거고
함수에는 이 address에 접근해서
원래 있던 오브젝트를 고쳐 준 거죠
그렇기 때문에 실제 이걸 패스하는 거는
레퍼런스에요
그런데 이제 재밌어지는 게 뭐냐면
그에 비해 자바에서 integer를 패스할 때는
뭐 float이나 그런 기본 타입들
그거는 값으로 들어가요
그래서 만약 int를 넣고 그 int 값을
function에서 바꾸더라도 원래 값은 안 바뀌어요
눈으로 보기에는 똑같아 보이는데
기본 타입이냐 아니면 오브젝트 타입이냐(에 따라)
실제 하나는 포인터를 전달하는 거고
하나는 값을 전달한다는 거죠
뭐 그래서 어쨌든 간에 포인터로 이제 생길 수 있는
문제는 고쳐 놓은 거에요
그리고 포인터로 언제나 값이 아니라
레퍼런스를 전달하기 때문에
그니까 오브젝트는 언제나 값이 아니라
레퍼런스를 전달하기 때문에
속도의 성능 저하
복사 때문에 일어나는 것도 많이 줄인 거고
그래서 이렇게 고치고 아 좋다라고 넘어간 거죠
근데 이제 C++은 그거를..
아 둘 다 장점을 살리자
당연히 포인터라는 게 존재하면은 쓸 데가 있는 거고
포인터 연산을 하는 거 되게 중요한 경우가 있거든요?
지금 여기서 메모리 가리키고 있다가
다음 메모리 가리켜서 읽는다거나?
이런 여러 가지 장점들이 있기 때문에
포인터는 살려 두고
대신 포인터를 쓸 때 조금 위험한 거를 막자
그게 전부였어요
그 대표적인 예가
함수에 포인터를 집어넣었어 그러면
그 함수에서 포인터로 이상한 짓을 한다거나
다른 주소로 가서 뭔가를 한다거나
왜냐면 포인터를 받은 거에다가 +1 하면은
다음 주소로 넘어가거든 거기다 막 쓰기도 하거든요?
아 그런 게 좀 위험하구나 그러면 그게 안 되게 막자
그래서 막은 게 레퍼런스에요
레퍼런스는 그냥..
보통 포인터는 스타 쓰는데, 별표(' * '),
이거는 ampersand(' & ') 넣잖아요?
그럼 뭐냐면
실제 가리키는 주소는 변할 수가 없는 거에요
내가 이 변수는 이 오브젝트를 가리키는 건데
그래서 오브젝트는 하나고 여러 가지 변수,
그니까 그건 지금 포인터죠 그걸 레퍼런스로 만든 거고
함수에 패스할 때도 레퍼런스를 패스하면은
자바처럼 똑같이 도는 거죠
자바하고 똑같이 돌긴 했지만
나중에 니가 정말 포인터 갖다가 이상한 짓을 해야 될
경우가 있으면 해라 그러고 놔둔 거에요
그게 첫 번째 레퍼런스 쓰는 이유
두 번째는,
함수에서 이제 포인터를 받는 건 좋아요
왜냐면 아까 말한 것처럼 pass-by-reference니까
복사가 아니라 레퍼런스를 전달해 주는 거니까
근데 문제는 뭐냐면 내가 포인터를 함수에서 받는 순간
어느 미친놈이 null을 집어넣을 수 있잖아요
심지어는
왜냐면 뭐 함수..
컴파일이 되니까
니가 라이브러리 만들었어?
이 라이브러리가 두 변수 swap하는 거야
어 근데 포인터를 받네?
난 null을 집어넣어야지
그럼 그 순간 null에 못 쓰니까 뻑이 나 버리거든요
이런 경우를 막아야 돼서
레퍼런스가 들어오면
null pointer가 들어올 가능성은 없으니까 아예
그래서 그거를 null이 아니라는 걸 표현하기 위해도
그렇게 한 거에요
그래서 C++로 넘어오면서 많은 사람들이 이제
포인터를 쓰기보다는 레퍼런스를 쓰라
라는 식으로 얘기가 갔어요
니가 정말 포인터 연산이 필요한 경우가 아니라면은
근데 이제 되게 재밌어지는 게 이런 부분이 뭐냐면
C++이 여기까지 한 거고 여기서 하나를 더 나갔으면
좋았는데 한 가지 문제가 있어요
그 예를 들어서 이런 함수가 있다고 생각을 해 봐요
어떤.. 보자
벡터 더하기 함수
그니까 벡터 더하기 함수인데
아 벡터 나누기로 하죠
벡터 나누기 함수인데
나누기.. 그니까
분모가 0이면은 문제가 생기잖아요 모든 나누기에는?
그래서 return 값으로는 boolean을 반환하는 거에요
그래서 boolean으로 이게 나누기를
성공했냐 안 했냐를 반환하고
그럼 두 벡터를 더하는(나누는) 거니까
매개변수로 일단 입력 변수로 뭐 a, b를 받아야겠고
그리고 return은 boolean으로 하기 때문에
output 변수를 따로 또 받아야 돼요
그럼 매개변수가 세 개가 되는 거에요
a, b, 그리고 output
이렇게 세 개가 되는데
그럼 이제
이 중의 아무거나라도
null이 된다는 건 말이 안 되잖아요
그러면 모두 다 레퍼런스로 받는 거에요
레퍼런스 받어 그럼 어떻게 돼
그러면
bool TryVectorDivide(Vector& a, Vector& b, Vector& out)
이 되는 거에요
그 순간 보면은
뭐 function parameter 이름은 제대로 정해 놨으니까
function header를 보면은
아 그래 이게 이런 함수구나 생각을 하게 돼요
근데 재밌는 거는
누군가 그 함수를 써서 코딩을 해 놨어요
예를 들어서, TryVectorDivide( )하고
매개변수를 넣는데 x, y, z를 넣어 버린 거야 그냥
아니면 a, b, c를 넣거나
그러면 함수 헤더를 실제 보지 않고
이 코드만 보는 순간
어떤 놈이 아웃이고 어떤 놈이 인풋이고
이게 구분이 안 돼요
그럼 이제 코드를 읽는 순간
readability가 떨어지는 거거든요 어떤 의미에서는
그러면 이제
"아 그러면 코드를 호출하는 사람이 이름을 잘 짜면 돼죠"
물론 이름을 잘 짜면 돼요
근데 그런다는 보장은 없잖아
내가 나중에 남이 짜 놓은 코드
코드 리뷰를 봤는데 못 잡았어
나중에 보다 코드를 보게 됐는데
IDE도 아니고 웹에서 다른 코드를 리뷰하다가
그 코드가 같이 보인 거에요
그럼 보면서 이게 과연 제대로 들어가고 있는 걸까
이런 고민을 할 수도 있고
아니면 뭐가 버그가 있다고 그랬는데
내가 IDE가 없고 비주얼 스튜디오가
당장 웹으로 가서 repo에서만 봐야 될 때
보면서, 이건 뭘까..
이런 고민을 할 수밖에 없거든요
그래서 이런 걸 좀 더 명확하게 하기 위해서
C# 같은 경우는, out parameter 같은 경우에는
매개변수를 집어넣을 때
차라리 out이라고 따로 넣어 주게 되어 있어요
C#은 제가 전에도 말했지만, language 디자인한 사람이
굉장히 뛰어난 사람인 것 같아요
굉장히 사람에 대한 이해력도 높고
그래서 굉장히 잘 만든 언어고
C++은 그 정도도 못 갔고
뭐 자바는 그거보다 못 갔던 거고 사실은
더 옛날..
옛날은 아닐 텐데
어쨌든 뭐 못 갔던 거죠 둘 다
그래서
C++에서 근데 재밌는 게 뭐냐면
포인터가 있기 때문에
이거를 구분할 수 있는 방법이 있더라고요
그리고 실제 이 코딩 스탠다드는 둠(Doom) 만든 회사
id Software에서 쓰던 코딩 스탠다드에요
그래서 어떤 식으로 만드냐면은
모든 입력 매개변수는 다 레퍼런스다
하지만 입력이 아니라 output되는 매개변수는
반드시 포인터로 넣어라라는 식으로 얘기를 해요
그러면 지금 말했던 벡터 함수가 어떻게 변하냐면은
bool TryVectorDivide( )
이렇게 들어가고
첫 번째가 입력 변수였죠 그럼 Vector& a,
두 번째가 또 입력 변수죠 Vector& b에요.
세 번째는 Vector c인데 문제는 레퍼런스가 아니라
주소를 넣어주는 거잖아요
아 잠깐 말을 잘못했다
호출할 때는 어떻게 들어가냐면
말을 잘못했어요
bool TryVectorDivide( , , , )이기 때문에
a, b, c가 벡터 타입이고
그러면 a를 그냥 넣어주죠
왜냐면은 이게 받는 타입이 레퍼런스 받으니까
얘를 넣어주면 레퍼런스를 받아가죠
b도 두 번째 넣어줘요
c를 넣을 때는 포인터를 받기 때문에
c는 벡터잖아요?
근데 포인터를 받는다는 건
address를 받는다는 거거든요?
그러면 앞에 address 연산자를 넣어주면 돼요
그니까 a, b, &c가 들어가요
그러면 나중에 코드를 보는 순간에도, 어 얘는 ampersand
붙었네? 얘는 out이네?라고 딱 알 수 있는 거에요
그래서 이런 거를 코딩 스탠다드로 정의해서 코드를
누구나 다 쉽게 읽을 수 있게 만드는 게 그 목적이거든요
C++에서 그렇게 하는 사람들이 있고
안 하는 사람들도 있고
이거는 뭐 다 한다고는 못하겠지만
제 코딩 스탠다드에서는 추구하고 있는 거에요
왜냐면은 코드를 보는 순간
깔끔하게 이게 out이고 아닌 걸 알고
누가 나중에 코드를 바꾸더라도
그런 코딩 스탠다드를 만드는 경우도 있어요
output 변수는 무조건 제일 먼저 오고
그 다음에 input 변수가 와야 된다
왜냐면은 보통 함수 호출하고 리턴 받으면
왼쪽으로 대입을 하니까
그런 식으로 해서 out을 먼저 넣는 경우도 있거든요
그럼 코드를 짤 때만 봐도,
어? ampersand가 중간에 붙었네?
왜 input, output이 섞여있지?
한 쪽으로 몰아라고
코딩 리뷰를 보기도 되게 쉽고
그래서 이제
그니까 readability를 높이는 과정이죠
이게 input이고 이게 output인 걸 확실하게 알 수 있게
근데 여기서 이 방식으로 갔을 때 한 가지 문제는 뭐냐면
그 순간 이제 output 변수에 null을 집어넣는
이상한 애들이 생긴다는 거죠
그럼 이제
아 null 체크 어떻게 하냐
뭐 두 가지 방식 중의 하나에요
아예 null이 들어왔는지 확인해서
boolean false를 반환해 버리던가
아니면은 null은 무조건 안 들어온다는 가정 하에
assert를 걸고 디버그 중에 잡는다든가
이 라이브러리가 내부에서만 쓰는 라이브러리면
충분히 그럴 수 있죠
허나 이 라이브러리가 외부에 파는 라이브러리라면 그게
null이 들어오는 순간 exception을 던지기도 해야겠죠
그래서
제가 예전에 exception 비디오도 몇 번 만들었는데
아 그냥 null이 들어오면 문제가 생기니까
exception을 박아야겠다 이런 자세는 안 좋고
그냥 이 코드가 다 우리가 컨트롤할 수 있는 코드고
외부에 나갈 일이 없는 코드고
그 상황에서 null이 여기 들어오는 거는 절대 안되는 건데
단지 우리가 지금 이런 코딩 스탠다드를 쓰고
이런 표준을 써 갖고 문제가 생기는 거기 때문에
이건 assert의 문제다
절대 생길 수 없는 일
그럼 assert를 박고 디버깅 중에 잡는 게 맞는 거고
절대 말이 안 되는 거지만
내가 이 라이브러리를 외부에 준다면
외부 사람들이 정말.. 우리 회사가 아닌
소스 코드 접근이 없는 다른 회사를 얘기하는 거에요
얘네들이 어떻게 쓸지를 모르잖아요
어떻게 뻑을 낼지도 모르고 그럼 그런 경우에는
내가 컨트롤할 수 있는 범위와
못하는 범위가 분명히 갈리는 경계잖아요
그럼 그때는 exception을 쓰는 거에요
근데 이제
제가 exception 얘기를 하면은
요즘 점점 exception 방향이 이렇게 가고 있어요
제가 얘기한 지 벌써 한 일 년이 넘은 것 같은데
최근 들어 똑같은 얘기를 하는 사람을
점점 많이 보고 있어요
그리고 이제
exception도 굉장히 사람들이.. 어, 새로운 거야!
라고 하면서 굉장히 이상하게 쓰다가
도무지 인간이 못 쓸 정도로 깽판치고 나서
이제 아 아니다 exception을
굉장히 소신있게 써야 되는 거다를 깨달아서
사람들이 점점 이제
제가 말한 방향으로 많이 돌아오고 있고
그런데
재밌는 거는 이제
그 정도 생각을 못 하는 사람들은
여전히 exception이 최고야라고 우길 수밖에 없죠
왜냐면 자기가 아는 건 그게 전부고
그 이상의 생각을 못 하는 경우도 있으니까
그래서 exception의 방향은
이제 점점 그렇게 잡혀가고 있는 것 같아요
뭐 아직
뭐라 그럴까
아직 그.. 대다수는 exception 떡칠을 하지만
왜냐면 세상에 굉장히 많은
exception 쓰는 언어 예제들이 잘못돼 있고
요즘 나오는 좀 괜찮은 언어로 괜찮게 문서 다듬는
그런 회사에서 나온 exception은 좀 더 괜찮긴 한데
그게 아니라 그냥 중구난방식으로, 예전에 처음 exception
나올 때 나왔던 그런 언어들은
여전히 exception practice 개판이고
그런 게 너무 많아 갖고
그리고 뭐 exception이 나은 이유를 설명하면서
말도 안 되는.. 그 뭐랄까
exception 없는 코드 갖다 놓고
exception으로 나아진다고 고쳐 놨는데
실제는 exception으로 고쳐도 똑같은 문제가 생기지만
함수를 이렇게 저렇게 바꿨기 때문에
다르게 보이게 만들고 exception이 뛰어나다
이렇게 외치는 되게 유명한 책도 봤고
보면서,
아 참 세상에 약 파는 사람이 많다는 생각을 했어요
아 뭐 어쨌든 얘기가 여기까지 흘러왔는데
뭐 할려고 했던 얘기는 결과적으로는
C++에서 레퍼런스하고 포인터를
매개변수로 어떻게 쓰느냐의 얘기였던 것 같아요
input 매개변수는 반드시 레퍼런스로 쓰고
그리고 input 매개변수가 변하지 않는다면
const 붙이는 것도 잊지 말고요
ouput 매개변수는
포인터로 쓰자
제 코딩 스탠다드고
제가 그냥 밑에 붙여 놓을게요
아마 제
공개돼 있는 코딩 스탠다드이기 때문에
제가 Google Docs에 써 갖고 냈던 거기 때문에
아직도 마음에 안 들 때마다 고치고는 있는데
어 일단 그렇게 하고 있어요
그리고 그거 외에도
제가 C# 코딩 스탠다드도 있거든요
제가 따로 하는 회사가, C# 회사가 또 하나 있기 때문에 CTO로 있는 회사가
거기도 그 코딩 스탠다드를 따르고 있어요
맨날 고민하고
비주얼 스튜디오 버전 올라가 갖고 이제
제 코딩 스탠다드가 가끔
비주얼 스튜디오가 안 좋아할 때가 있어요
naming convention에 안 맞아 새 버전에서
그러면 이제 따라가고
개인적으로 IDE가 해 주는 부분을 거슬러 가면서까지
코딩 스탠다드를 만드는 거 되게 싫어하거든요
그러면 이제 모든 사람이 인스톨 할 때마다
새로운 코딩 스탠다드 설정해야 되고
그런 그 말도 안 되는 것들
되게 싫어하기 때문에
그러고 있어요 그래서
그 링크는 밑에 걸게요
오늘은 그 정도면 된 것 같고
앞으로 기회가 될 때마다
제가 쓰고 있는 코딩 스탠다드를 하나씩 얘기하면서
그거에 대한 이유를 설명을 할게요
뭐
제 코딩 스탠다드 문서에 적지는 않아요
안 적는 이유가
그거 남들 다 이해시키려고 하긴 귀찮고
또 이해 못 하는 애들이 이해한다 그러고
엉뚱한 얘기를 하기 때문에
그 흔히들 말하는 게 있어요 이제
진짜 코드 몽키급의 사람들은 그냥 쓰는 게 맞고
하라는 대로 쓰는 게 맞고
엔지니어급의 사람들은 지가 이상하다 그러면
그때 이제 이게 이상한 이유를 얘기하겠지만
대부분의 경우에 그 사람들은 이 코딩 스탠다드가
왜 있는지 알고 그거의 가치를 안다는 거죠
그래서
지금 제가 한 말이 아니라 예전에 무슨 아키텍처 클래스
들었을 때 어떤 강사님이 하신 말이에요
그래서
코딩 스탠다드 쓸 때는 절대 이유를 쓰지 말아라
어차피 코딩 스탠다르를 보고 익히고 따르는 애들은
다 코드 몽키들이고
걔네들이 이해를 할 걸로 생각하지 마라
라는 식으로 얘기를 했어요
하지만 엔지니어급의 애들이면
이미 니 코딩 스탠다드를 이해할 거다
보면 좀 되게 웃긴 말인데
그래서
문서가 길어지는 걸 원치 않기 때문에도
저는 짧게 쓸 거고
설명은 그냥 비디오에서 간간이 하는 걸로
대체하려고 그래요
음 그 정도면 된 것 같네요
예 포프였습니다