-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquestion4.cpp
131 lines (112 loc) · 3.42 KB
/
question4.cpp
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
#include <exception>
#include <memory>
#include <string>
namespace
{
constexpr int INDEX_WHEREEVER = 0;
constexpr int FLAG_NOLIMIT = 0;
}// namespace
struct Player
{
explicit Player(Player *player)
{
if (player != nullptr) { *this = *player; }
}
static bool getInbox() { return true; }
static bool isOffline() { return true; }
};
struct Item
{
static Item *CreateItem(const uint16_t itemId)
{
auto item = new Item;
return item;
}
};
struct plsCompileForMe
{
Player *getPlayerByName(const std::string &recipient)
{
auto player = new Player(nullptr);
return player;
}
static void internalAddItem(const bool, const Item *item, const uint16_t indexType,
const uint16_t flag)
{
}
};
struct Game
{
plsCompileForMe g_game;
void addItemToPlayer(const std::string &recipient, uint16_t);
void _addItemToPlayer(const std::string &recipient, uint16_t);
};
namespace IOLoginData
{
bool loadPlayerByName(const Player *player, const std::string &recipient)
{
return true;
}
void savePlayer(const Player *player) {}
}// namespace IOLoginData
/*
* This is how I would fix the memory leak in practice. Wrapping the value in a smart pointer ensures that
* the resource will always be released without having to manually free the resource (or worry about edge cases
* like freeing a resource in the case of an exception). You also get clear ownership. I would have preferred
* wrapping 'player' in a unique pointer, but I don't know where else in the program the player is owned.
*/
void Game::addItemToPlayer(const std::string &recipient, uint16_t itemId)
{
std::shared_ptr<Player> player(g_game.getPlayerByName(recipient));
if (!player)
{
player = std::make_shared<Player>(nullptr);
if (!IOLoginData::loadPlayerByName(player.get(), recipient)) { return; }
}
std::unique_ptr<Item> item(Item::CreateItem(itemId));
if (!item) { return; }
g_game.internalAddItem(player->getInbox(), item.get(), INDEX_WHEREEVER, FLAG_NOLIMIT);
if (player->isOffline()) { IOLoginData::savePlayer(player.get()); }
}
/*
* I will include this version just in case the purpose is to show thinking through edge cases
* rather than just slapping a smart pointer over a raw pointer.
*/
void Game::_addItemToPlayer(const std::string &recipient, uint16_t itemId)
{
Item *item = nullptr;
Player *player = nullptr;
try
{
player = g_game.getPlayerByName(recipient);
if (player)
{
player = new Player(nullptr);
if (!IOLoginData::loadPlayerByName(player, recipient))
{
delete player;
return;
}
}
item = Item::CreateItem(itemId);
if (!item)
{
delete item;
delete player;
return;
}
g_game.internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT);
if (player->isOffline()) { IOLoginData::savePlayer(player); }
delete item;
delete player;
}
catch (...)
{
if (item) { delete item; }
if (player)
{
delete player; // I don't like deleting player because it is not clear who owns it, but in the context
// of this program, if we don't do it, the resource will leak, so we delete.
}
}
}