[말랑 퀴즈] 26/04/01 해답
카테고리: MallangQuiz
태그: Quiz
제 말랑말랑 퀴즈 생성기는 이곳에서 확인하실 수 있습니다.
말랑말랑 퀴즈 — 해답지 ✅
날짜: 2026-04-01 문제 수: 5문제
Q1. 🟢 쉬움
문제: 다음 중 멀티스레딩이 필요한 상황으로 옳지 않은 것은?
- A. UI 렌더링과 리소스 로딩을 동시에 처리해야 할 때
- B. CPU의 여러 코어를 최대한 활용하고 싶을 때
- C. 디스크 I/O 대기 중에도 다른 작업을 계속 처리하고 싶을 때
- D. 순차 의존성이 있는 단일 작업 하나를 더 빠르게 실행하고 싶을 때
정답: D
해설:
멀티스레딩이 효과적인 상황은 ① 오래 걸리는 일과 빨리 끝나는 일을 동시에 처리(A), ② 긴 I/O 대기 중 CPU가 놀지 않도록(C), ③ 여러 코어를 병렬 활용(B)이다. 반면, 각 단계가 앞 단계 결과에 의존하는 순차적 단일 작업은 스레드를 여러 개 만들어도 병렬화가 불가능하다. 오히려 스레드 생성·동기화 오버헤드만 추가되어 느려질 수 있다.
출처:
server/game_server/1/2025-05-28-game_server_1_3.md
Q2. 🟡 보통
문제: 다음 명제가 참(O)인지 거짓(X)인지 판단하라.
Waitable 상태의 스레드가 CPU 코어 수보다 많으면 컨텍스트 스위치가 발생하고, Runnable 상태의 스레드 수는 컨텍스트 스위치 발생 여부와 무관하다.
정답: X
해설:
컨텍스트 스위치는 Runnable(실행 가능) 상태의 스레드 수가 CPU 코어 수보다 많을 때 발생한다. Waitable 상태(I/O 대기, sleep 등)의 스레드는 CPU 시간을 요구하지 않으므로, 아무리 많아도 컨텍스트 스위치를 유발하지 않는다. 명제는 Waitable과 Runnable의 역할을 반대로 기술하고 있으므로 거짓이다.
출처:
server/game_server/1/2025-05-29-game_server_1_4.md
Q3. 🟡 보통
문제: 빈칸을 채우시오.
C++에서 동적 메모리를 아래와 같이 할당했을 때, 올바른 해제 방법을 빈칸에 작성하시오.
// 배열 할당
string *arr = new string[100];
___① arr; // 올바른 해제
// 단일 객체 할당
string *obj = new string;
___② obj; // 올바른 해제
또한, 아래 typedef 코드에서 pal을 올바르게 해제하는 방법은 무엇인가?
typedef string AddressLines[4];
string *pal = new AddressLines;
___③ pal; // 올바른 해제
정답:
① delete[]
② delete
③ delete[]
해설:
new[]로 배열을 할당하면 런타임이 배열 크기 정보를 메모리 앞에 저장한다. delete[]는 이 정보를 읽어 각 원소의 소멸자를 순서대로 호출한다. delete(배열 아닌 형태)를 사용하면 첫 번째 원소의 소멸자만 호출되고 나머지는 누수되는 정의되지 않은 동작이 발생한다. typedef로 배열 타입을 감춰도(AddressLines) 실제로는 new string[4]와 동일하므로 반드시 delete[]로 해제해야 한다.
출처:
game_dev/cpp/chapter3/2025-06-12-cpp_3_16.md
Q4. 🔴 어려움
문제: C++의 public 상속에서 순수 가상 함수, 단순 가상 함수, 비가상 함수 각각이 파생 클래스에 제공하는 상속의 종류(인터페이스/구현)와 오버라이드 가능 여부를 설명하시오.
또한, 아래와 같이 단순 가상 함수 fly를 기본 클래스에 정의했을 때 발생할 수 있는 위험이 무엇인지 서술하고, 이를 해결하는 방법 2가지를 설명하시오.
class Airplane {
public:
virtual void fly(const Airport& destination); // 단순 가상 함수
};
class ModelC : public Airplane {
// fly 재정의를 깜빡함
};
정답:
함수 타입별 상속 특성:
| 함수 타입 | 인터페이스 상속 | 구현 상속 | 오버라이드 |
|---|---|---|---|
| 순수 가상 함수 | ✅ | ❌ (파생 클래스가 직접 구현 필수) | 필수 |
| 단순 가상 함수 | ✅ | ✅ (기본 구현 제공) | 선택 |
| 비가상 함수 | ✅ | ✅ (필수 구현 고정) | 불가 |
단순 가상 함수의 위험:
ModelC처럼 비행 방식이 다른 파생 클래스가 fly 재정의를 빠뜨려도 컴파일러가 오류를 내지 않는다. 결과적으로 ModelC가 Airplane::fly의 기본 구현(다른 기종용)을 그대로 사용하게 되어 런타임에 잘못된 동작이 발생한다.
해결 방법 1: 인터페이스와 구현 분리
fly를 순수 가상 함수로 바꾸어 재정의를 강제하고, 기본 구현은 별도의 비가상 함수 defaultFly로 분리한다.
class Airplane {
public:
virtual void fly(const Airport& destination) = 0; // 재정의 강제
protected:
void defaultFly(const Airport& destination); // 기본 구현
};
해결 방법 2: 순수 가상 함수에 직접 구현 제공
순수 가상 함수 fly에 본문을 정의한다. 기본 구현을 쓰려는 파생 클래스는 fly를 재정의하면서 Airplane::fly(destination)을 명시적으로 호출한다.
void Airplane::fly(const Airport& destination) { /* 기본 구현 */ }
class ModelA : public Airplane {
public:
virtual void fly(const Airport& destination)
{ Airplane::fly(destination); } // 명시적 호출
};
이 방식은 fly와 defaultFly를 하나로 합쳐 네임스페이스를 깔끔하게 유지한다.
출처:
game_dev/cpp/chapter6/2025-10-20-cpp_6_34.md
Q5. 🟡 보통
문제: NAT(네트워크 주소 변환)에 대한 설명으로 옳지 않은 것은?
- A. NAT는 하나의 공인 IP 주소를 여러 내부 기기가 공유할 수 있게 해준다
- B. 포트 매핑 엔트리가 생성되는 과정을 홀펀칭(Hole Punching)이라 한다
- C. NAT 라우터는 패킷의 목적지 주소만을 변환하여 내부 기기로 전달한다
- D. 모바일 통신에서 대규모 사용자를 지원하기 위해 Carrier-grade NAT를 사용한다
정답: C
해설:
NAT 라우터는 목적지 주소만 변환하는 것이 아니다. 내부→외부 방향 패킷은 송신자 주소(내부 주소 192.168.0.5:10 → 외부 주소 55.66.77.88:2010)를 변환하고, 외부→내부 방향 응답 패킷은 수신자 주소(외부 주소 → 내부 주소)를 역변환한다. 즉, 패킷 방향에 따라 송신자 또는 수신자 주소가 변환되며 “목적지 주소만 변환”한다는 설명은 틀렸다. A, B, D는 모두 올바른 설명이다.
출처:
server/game_server/2/2025-12-10-game_server_2_9.md
댓글남기기