[말랑 퀴즈] 26/08/22 문제
카테고리: MallangQuiz
태그: Quiz
제 말랑말랑 퀴즈 생성기는 이곳에서 확인하실 수 있습니다.
말랑말랑 퀴즈 📝
날짜: 2026-08-22 문제 수: 5문제
Q1. 🟡 보통
Widget은 Bitmap 객체를 힙에 들고 있는 클래스이고, pb는 그것을 가리키는 포인터 멤버다. 아래는 이 클래스의 복사 대입 연산자다.
class Widget {
Bitmap* pb; // 힙에 할당된 Bitmap을 가리킨다
...
};
Widget& Widget::operator=(const Widget& rhs) {
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
(1) 이 코드는 두 가지 상황에서 위험하다. 각각이 무엇이며 왜 위험한지 설명하시오.
(2) 함수 맨 앞에 아래 한 줄을 추가하는 방식이 있다. 이 방식의 한계는 무엇인가?
(3) 위 한 줄 없이도 (1)의 두 상황을 모두 안전하게 만드는 방법이 있다. 고친 코드를 작성하고, 왜 안전해지는지 설명하시오.
출처:
game_dev/cpp/chapter2/2025-06-07-cpp_2_11.md
📝 내 풀이:
(1)
- delete pb; 에서 예외가 발생하는 상황
- new 연산자에서 예외가 발생하는 상황
기존 pb를 백업해두지 않은 상태에서 pb를 삭제하고 대입하고 있으며, new 연산자에서 예외가 발생하면 메모리 누수가 발생할 수 있기 때문이다.
(2)
if (this == &rhs) return *this;
어디까지 동일한 객체라고 판단할 것인지 경계가 모호하다. (일부 변수만 같으면 같은가? 아니면 전체가 같아야 하는가?)
(3)
Widget& Widget::operator=(const Widget& rhs) {
Bitmap origin = pb;
Bitmap value = rhs;
try {
swap(pb, value);
}
catch(const std::exception e&) {
pb = origin;
}
return *this;
}
swap 말고도 객체 생성 시 두개의 코드 줄로 나누는 방식도 있었는데 정확히 기억은 안난다. 안전해지는 이유는 기존 데이터 수정은 없애, 예외 처리를 하게 두는 것이다.
Q2. 🟡 보통
아래 코드에서 Airplane::fly는 단순 가상 함수(= 0이 붙지 않은 virtual 함수)이고, 기본 구현이 제공되어 있다.
class Airplane {
public:
virtual void fly(const Airport& destination); // 단순 가상 함수
...
};
// 목적지로 비행기를 날려보내는 기본 구현
void Airplane::fly(const Airport& destination) { ... }
class ModelA : public Airplane { ... }; // 기본 구현을 그대로 씀
class ModelB : public Airplane { ... }; // 기본 구현을 그대로 씀
그런데 나중에 추가된 ModelC는 비행 방식이 완전히 다른데도 fly 재정의를 빼먹었다.
class ModelC : public Airplane {
... // fly를 재정의하지 않음
};
int main() {
Airport PDX(...);
Airplane* pa = new ModelC;
pa->fly(PDX); // ← 무슨 일이 벌어지는가?
}
이 상황에 대한 설명으로 가장 올바른 것은?
- A.
ModelC가fly를 재정의하지 않았으므로new ModelC지점에서 컴파일 에러가 발생한다. - B. 단순 가상 함수는 인터페이스와 함께 기본 구현까지 물려주기 때문에 재정의를 강제할 방법이 없고,
ModelC는 자신에게 맞지 않는Airplane::fly를 그대로 쓰게 된다.fly를 순수 가상 함수로 바꾸고 기본 동작을defaultFly같은 별도 함수로 분리하면 재정의를 강제할 수 있다. - C.
fly를 비가상 함수로 바꾸면 파생 클래스마다 각자의 구현을 제공하도록 강제할 수 있으므로 이 문제가 해결된다. - D.
Airplane은 가상 함수를 가지고 있으므로 추상 클래스이며, 따라서Airplane* pa = new ModelC;자체가 컴파일되지 않는다.
출처:
game_dev/cpp/chapter6/2025-10-20-cpp_6_34.md
📝 내 선택: B
Q3. 🟢 쉬움
빈칸을 채우시오.
auto의 형식 연역은 대체로 템플릿 형식 연역과 똑같이 작동하지만, 딱 한 가지 예외가 있다. 중괄호 초기치를 만났을 때다.
int x1 = 27; // 형식 = int
int x3 = { 27 }; // 형식 = int
auto y1 = 27; // 형식 = ① ___
auto y3 = { 27 }; // 형식 = ② ___
auto 형식 연역은 중괄호 초기치가 ②를 나타낸다고 가정하지만, 템플릿 형식 연역은 그렇게 가정하지 않는다. 그래서 아래 두 경우에는 auto 형식 연역이 아니라 ③ ___ 형식 연역 규칙이 적용되어 컴파일이 거부된다.
auto createInitList() {
return { 1, 2, 3 }; // ⚠️ 오류
}
std::vector<int> v;
auto resetV = [&v](const auto& newValue) { v = newValue; };
resetV({ 1, 2, 3 }); // ⚠️ 오류
출처:
game_dev/moderncpp/1/2026-04-03-moderncpp_1_2.md
📝 내 답: int, vector
Q4. 🔴 어려움
UE5의 CharacterMovementComponent를 확장해 Sprint를 이동 패킷의 FLAG_Custom_0 비트에 실었다. 클라는 매 프레임 FSavedMove(이동 스냅샷)를 만들고, 엔진은 보류 중인 Move 하나와 새로 만든 Move 하나를 합칠 수 있는지 CanCombineWith로 검사한다. 합쳐지면 두 프레임이 하나의 압축 플래그로 전송된다.
속도 계산은 이렇게 되어 있다.
float UEPCharacterMovement::GetMaxSpeed() const
{
if (bWantsToSprint && IsMovingOnGround()) return SprintSpeed; // 650
if (bWantsToAim) return AimSpeed; // 200
return Super::GetMaxSpeed(); // 600
}
엔진의 부모 구현은 이미 두 Move의 MaxSpeed를 비교해 다르면 합치지 않는다.
// FSavedMove_Character::CanCombineWith
if (!FMath::IsNearlyEqual(MaxSpeed, NewMove->MaxSpeed, MaxSpeedThresholdCombine))
{
return false;
}
그런데도 아래처럼 오버라이드를 추가했다.
bool FSavedMove_EPCharacter::CanCombineWith(const FSavedMovePtr& NewMove,
ACharacter* Character, float MaxDelta) const
{
FSavedMove_EPCharacter* Other = static_cast<FSavedMove_EPCharacter*>(NewMove.Get());
if (bSavedWantsToSprint != Other->bSavedWantsToSprint) return false;
if (bSavedWantsToAim != Other->bSavedWantsToAim) return false;
return FSavedMove_Character::CanCombineWith(NewMove, Character, MaxDelta);
}
(1) 부모가 이미 MaxSpeed를 비교하고 있는데도 이 오버라이드가 필요한 이유를 설명하시오. 어떤 상황에서 부모 검사만으로는 부족해지는가?
(2) 그 상황에서 오버라이드가 없으면 최종적으로 무슨 문제가 발생하는지, 순서대로 설명하시오.
출처:
game_dev/devlog/2026-02-10-EP_Replication-1.md
📝 내 풀이:
(1) Sprint/Aim 같은 플래그는 합쳐질 수 없기 때문이다. 하나만 달라도 합치는게 불가능하다.
예를 들어 합쳐지는 범위가 0.5s라 치자. 0s에 sprint==1, 0.3s에 sprint==0가 되면 합칠 수 없다.
(2) 플래그가 무시되는 상황이 발생한다.
- 합쳐지는 범위는 0.5s
- 0s 걷기
- 0.1s 달리기
- 0.3s 걷기
이 경우 달리기가 취소된다.
Q5. 🔴 어려움
다음 명제가 참(O)인지 거짓(X)인지 판단하라.
typedef는 그 자체로는 템플릿화할 수 없지만, 아래처럼 구조체로 감싸면 템플릿화할 수 있다.template<typename T> struct MyAllocList { typedef std::list<T, MyAlloc<T>> type; };따라서 클래스 템플릿 안에서도 아래처럼 쓸 수 있으며, 별칭 템플릿(
template<typename T> using MyAllocList = std::list<T, MyAlloc<T>>;)을 쓰는 것과 사용법상 차이가 없다.template<typename T> class Widget { private: MyAllocList<T>::type list; };
출처:
game_dev/moderncpp/3/2026-04-18-moderncpp_3_9.md
📝 내 답: X. 아니었던 것 같긴한데 기억이 잘 안난다.
댓글남기기