21. 가방이 가득 찬 상태에서 동시 다중 획득
난이도 하 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 가방이 가득 찬 상태에서 보상/획득이 동시에 여러 개 들어오는 상황
// ----------------------------------------------------------------------------
// 시나리오:
// - 인벤토리(가방)는 고정 칸 수(Capacity)를 가진다. 각 칸은 비어있거나(null)
// 아이템 하나를 담는다.
// - AddItem: 빈 칸을 찾아 아이템을 넣는다. 빈 칸이 없으면 실패.
// - 한 플레이어가 거의 동시에 여러 경로로 아이템을 받을 수 있다: 퀘스트 보상,
// 몬스터 드랍, 우편 일괄 수령 등. 이들은 서로 다른 워커 스레드에서 처리될 수 있다.
//
// 요구사항:
// - 같은 칸에 두 아이템이 들어가 한쪽이 사라지면 안 된다(아이템 유실 금지).
// - 빈 칸 수보다 많은 아이템이 "성공"으로 처리되면 안 된다(가짜 성공/초과 지급 금지).
// - 동시 획득에도 자료구조가 손상되거나 정의되지 않은 동작이 나면 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(동시 인터리빙 포함)
// 설명하고, 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
using System;
using System.Collections.Generic;
public class Item
{
public long Uid;
public int ItemId;
}
public class Inventory
{
private readonly Item[] _slots;
public int Capacity => _slots.Length;
public Inventory(int capacity) { _slots = new Item[capacity]; }
// 빈 칸을 찾아 아이템을 넣는다. 성공하면 true.
public bool AddItem(Item item)
{
// (A)
int free = FindFreeSlot();
if (free < 0) return false; // 가득 참
// (B)
_slots[free] = item;
return true;
}
private int FindFreeSlot()
{
for (int i = 0; i < _slots.Length; i++)
if (_slots[i] == null) return i;
return -1;
}
// 여러 보상을 한꺼번에 지급. 실제로 들어간 개수를 반환.
public int AddMany(IEnumerable<Item> items)
{
int granted = 0;
foreach (var it in items)
{
// (C)
if (AddItem(it))
granted++;
}
return granted;
}
} 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] C++ - 가방이 가득 찬 상태에서 보상/획득이 동시에 여러 개 들어오는 상황
// ----------------------------------------------------------------------------
// 시나리오:
// - 인벤토리(가방)는 고정 칸 수(capacity)를 가진다. 각 칸은 비어있거나(nullptr)
// 아이템 하나를 담는다.
// - addItem: 빈 칸을 찾아 아이템을 넣는다. 빈 칸이 없으면 실패.
// - 한 플레이어가 거의 동시에 여러 경로로 아이템을 받을 수 있다: 퀘스트 보상,
// 몬스터 드랍, 우편 일괄 수령 등. 이들은 서로 다른 워커 스레드에서 처리될 수 있다.
//
// 요구사항:
// - 같은 칸에 두 아이템이 들어가 한쪽이 사라지면 안 된다(아이템 유실 금지).
// - 빈 칸 수보다 많은 아이템이 "성공"으로 처리되면 안 된다(가짜 성공/초과 지급 금지).
// - 동시 획득에도 자료구조가 손상되거나 정의되지 않은 동작이 나면 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(동시 인터리빙 포함)
// 설명하고, 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <vector>
#include <memory>
#include <cstdint>
struct Item {
int64_t uid;
int itemId;
};
class Inventory {
public:
explicit Inventory(int capacity) : slots_(capacity) {}
int capacity() const { return static_cast<int>(slots_.size()); }
// 빈 칸을 찾아 아이템을 넣는다. 성공하면 true.
bool addItem(std::shared_ptr<Item> item) {
// (A)
int free = findFreeSlot();
if (free < 0) return false; // 가득 참
// (B)
slots_[free] = std::move(item);
return true;
}
// 여러 보상을 한꺼번에 지급. 실제로 들어간 개수를 반환.
int addMany(const std::vector<std::shared_ptr<Item>>& items) {
int granted = 0;
for (const auto& it : items) {
// (C)
if (addItem(it))
++granted;
}
return granted;
}
private:
int findFreeSlot() const {
for (int i = 0; i < static_cast<int>(slots_.size()); ++i)
if (!slots_[i]) return i;
return -1;
}
std::vector<std::shared_ptr<Item>> slots_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.