Skip to content

Commit 5e5605f

Browse files
committed
CMakeLists.txt:
- changed project version to 1.3. - enabled address sanitizer. CMakePresets.json: - added address sanitizer to 'unixlike-gcc-debug-github' configuration preset. problem_071_observable_vector_container.cpp: - changed observers_ from a list of shared_ptr to a list of weak_ptr (there was a circular dependency between a subject, keeping a list of shared_ptr to observers, and observers, keeping a shared_ptr to a subject; this was causing a memory leak).
1 parent 09dcffd commit 5e5605f

File tree

3 files changed

+42
-20
lines changed

3 files changed

+42
-20
lines changed

CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems
1717

1818

1919
project("the_modern_c++_challenge"
20-
VERSION 1.2
20+
VERSION 1.3
2121
DESCRIPTION "My solutions to the 100 problems of The Modern C++ Challenge, a book by Marius Bancila's (published by Packt)."
2222
HOMEPAGE_URL https://github.com/rturrado/the_modern_cpp_challenge.git
2323
LANGUAGES C CXX
@@ -40,7 +40,6 @@ endif()
4040

4141

4242
# Address sanitizer
43-
#[[
4443
if(ASAN_ENABLED)
4544
string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
4645
message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}\n")
@@ -51,7 +50,6 @@ if(ASAN_ENABLED)
5150
add_link_options(-fsanitize=address,undefined)
5251
endif()
5352
endif()
54-
]]#
5553

5654

5755
# Subdirectories

CMakePresets.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@
219219
"displayName": "gcc Debug (GitHub)",
220220
"description": "Target Unix-like OS with the gcc compiler, debug build type (GitHub)",
221221
"inherits": [
222+
"unixlike-gcc-debug-asan",
222223
"unixlike-gcc-debug-ccache",
223224
"unixlike-gcc-debug-coverage",
224225
"unixlike-gcc-debug-tests"

include/the_modern_c++_challenge/chapter_08_design_patterns/problem_071_observable_vector_container.h

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace tmcppc::data_structures {
2929
explicit notification(notification_type t)
3030
: id_{ id++ }
3131
, type_{ t }
32+
, index_of_changed_element_{ 0 }
3233
{}
3334
notification(notification_type t, size_t i)
3435
: id_{ id++ }
@@ -42,9 +43,9 @@ namespace tmcppc::data_structures {
4243
private:
4344
static inline size_t id{};
4445

45-
size_t id_{};
46-
notification_type type_{};
47-
size_t index_of_changed_element_{};
46+
size_t id_;
47+
notification_type type_;
48+
size_t index_of_changed_element_;
4849
};
4950

5051

@@ -60,7 +61,7 @@ namespace tmcppc::data_structures {
6061

6162
using group_t = std::string;
6263
using id_t = size_t;
63-
std::map<group_t, id_t> cache_{};
64+
std::map<group_t, id_t> cache_;
6465
};
6566

6667

@@ -78,14 +79,18 @@ namespace tmcppc::data_structures {
7879
explicit observer(std::ostream& os, std::shared_ptr<observable_vector<T>> sp_ov) noexcept
7980
: id_{ id_generator_("observer") }
8081
, os_{ os }
81-
, sp_ov_{ sp_ov }
82+
, sp_ov_{ std::move(sp_ov) }
8283
{}
84+
constexpr observer(const observer& other) = default;
85+
constexpr observer(observer&& other) = default;
86+
constexpr observer& operator=(const observer& other) = default;
87+
constexpr observer& operator=(observer&& other) = default;
8388
private:
8489
static inline group_id_generator& id_generator_{ group_id_generator::get_instance() };
8590

86-
size_t id_{};
91+
size_t id_;
8792
std::ostream& os_;
88-
std::shared_ptr<observable_vector<T>> sp_ov_{};
93+
std::shared_ptr<observable_vector<T>> sp_ov_;
8994
};
9095

9196

@@ -96,7 +101,12 @@ namespace tmcppc::data_structures {
96101
class concrete_observer_1 : public observer<T> {
97102
public:
98103
explicit concrete_observer_1(std::ostream& os, std::shared_ptr<observable_vector<T>> sp_ov) noexcept
99-
: observer<T>::observer{ os, sp_ov } {}
104+
: observer<T>::observer{ os, std::move(sp_ov) } {}
105+
constexpr concrete_observer_1(const concrete_observer_1& other) = default;
106+
constexpr concrete_observer_1(concrete_observer_1&& other) = default;
107+
constexpr concrete_observer_1& operator=(const concrete_observer_1& other) = default;
108+
constexpr concrete_observer_1& operator=(concrete_observer_1&& other) = default;
109+
~concrete_observer_1() = default;
100110
protected:
101111
void update(const notification& n) noexcept override {
102112
auto id{ observer<T>::get_id() };
@@ -112,7 +122,12 @@ namespace tmcppc::data_structures {
112122
class concrete_observer_2 : public observer<T> {
113123
public:
114124
explicit concrete_observer_2(std::ostream& os, std::shared_ptr<observable_vector<T>> sp_ov) noexcept
115-
: observer<T>::observer{ os, sp_ov } {}
125+
: observer<T>::observer{ os, std::move(sp_ov) } {}
126+
constexpr concrete_observer_2(const concrete_observer_2& other) = default;
127+
constexpr concrete_observer_2(concrete_observer_2&& other) = default;
128+
constexpr concrete_observer_2& operator=(const concrete_observer_2& other) = default;
129+
constexpr concrete_observer_2& operator=(concrete_observer_2&& other) = default;
130+
~concrete_observer_2() = default;
116131
protected:
117132
void update(const notification& n) noexcept override {
118133
auto id{ observer<T>::get_id() };
@@ -131,11 +146,14 @@ namespace tmcppc::data_structures {
131146

132147
[[nodiscard]] size_t get_id() const noexcept { return id_; }
133148

134-
void attach(const std::shared_ptr<observer<T>> observer) noexcept {
135-
observers_.insert(std::end(observers_), observer);
149+
void attach(const std::shared_ptr<observer<T>>& observer_sp) noexcept {
150+
observers_.insert(std::end(observers_), observer_sp);
136151
}
137-
void detach(const std::shared_ptr<observer<T>> observer) noexcept {
138-
observers_.remove_if([&observer](auto sp) { return sp->get_id() == observer->get_id(); });
152+
void detach(const std::shared_ptr<observer<T>>& observer_sp) noexcept {
153+
observers_.remove_if([&observer_sp](const auto& wp) {
154+
auto sp{ wp.lock() };
155+
return sp and sp->get_id() == observer_sp->get_id();
156+
});
139157
}
140158

141159
protected:
@@ -157,14 +175,19 @@ namespace tmcppc::data_structures {
157175
[[nodiscard]] bool is_observed() const noexcept { return not observers_.empty(); }
158176

159177
void notify(const notification& n) const {
160-
std::ranges::for_each(observers_, [&n](auto sp) { sp->update(n); });
178+
std::ranges::for_each(observers_, [&n](const auto& wp) {
179+
auto sp{ wp.lock() };
180+
if (sp) {
181+
sp->update(n);
182+
}
183+
});
161184
}
162185

163186
private:
164187
static inline group_id_generator& id_generator_{ group_id_generator::get_instance() };
165188

166-
size_t id_{};
167-
std::list<std::shared_ptr<observer<T>>> observers_{};
189+
size_t id_;
190+
std::list<std::weak_ptr<observer<T>>> observers_;
168191
};
169192

170193

@@ -187,7 +210,7 @@ namespace tmcppc::data_structures {
187210
constexpr observable_vector(InputIt first, InputIt last)
188211
: v_(first, last) {}
189212
constexpr observable_vector(std::initializer_list<T> init)
190-
: v_(init) {}
213+
: v_{ init } {}
191214

192215
constexpr observable_vector(const observable_vector& other)
193216
: subject<T>{ other }

0 commit comments

Comments
 (0)