Игорь Кудрин, «Используем неизменяемые данные и...
TRANSCRIPT
• Язык C++ предоставляет слишком много возможностей
template <typename T> T f(T&& t);
#define M(...) { __VA_ARGS__ }
class virtual
public decltype
const
auto a = [](){}; throw
• Язык C++ предоставляет слишком много возможностей
• Нет времени научиться использовать их правильно
• Язык C++ предоставляет слишком много возможностей
• Нет времени научиться использовать их правильно
• Следствие: сложный и ненадёжный код
• Не использовать лишнего • Множественное наследование • Макросы • Шаблоны • Исключения • Наследование реализации
• Не использовать лишнего • Упрощать интерфейс
• Минимум публичных методов • Избегать парных операций
• Не использовать лишнего • Упрощать интерфейс
• Минимум публичных методов • Избегать парных операций • Стабильное состояние
> gcc –Wall –std=c++11 x.cpp No warnings
std::vector<int> v = gen_v(); int s; for (int i : v) { s += i; } ... f(s); h(s);
> gcc –Wall –std=c++11 x.cpp No warnings > gcc –Wall –O –std=c++11 x.cpp warning: ‘s’ may be used uninitialized
std::vector<int> v = gen_v(); int s; for (int i : v) { s += i; } ... f(s); h(s);
std::vector<int> v = gen_v(); int s = 0; for (int i : v) { s += i; } ... f(s); h(s);
А вдруг? void f(int&);
const std::vector<int> v = gen_v(); const int s = std::accumulate(begin(v), end(v), 0); ... f(s); h(s);
const std::vector<int> v = gen_v(); const int s = std::accumulate(begin(v), end(v), 0); ... f(s); h(s);
• Код становится проще
const std::vector<int> v = gen_v(); const int s = std::accumulate(begin(v), end(v), 0); ... f(s); h(s);
• Код становится проще • Защищает от части ошибок
const std::vector<int> v = gen_v(); const int s = std::accumulate(begin(v), end(v), 0); ... f(s); h(s);
• Код становится проще • Защищает от части ошибок • Способствует рефакторингу
class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { return x_; } int Y() const { return y_; } void Move(int ox, int oy) { x_ += ox; y_ += oy; } private: int x_, y_; };
class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { Lock lock(mtx_); return x_; } int Y() const { Lock lock(mtx_); return y_; } void Move(int ox, int oy) { Lock lock(mtx_); x_ += ox; y_ += oy; } private: int x_, y_; mutable std::mutex mtx_; typedef std::lock_guard<std::mutex> Lock; };
// External synchronization is required! class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { return x_; } int Y() const { return y_; } void Move(int ox, int oy) { x_ += ox; y_ += oy; } private: int x_, y_; };
class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { return x_; } int Y() const { return y_; } Point Move(int ox, int oy) const { return Point(x_ + ox, y_ + oy); } private: int x_, y_; };
class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { return x_; } int Y() const { return y_; } Point Move(int ox, int oy) const { return Point(x_ + ox, y_ + oy); } private: int x_, y_; };
Point p(10, 20); p = Point(20, 10);
class Point { public: Point(int x, int y) : x_(x), y_(y) {} int X() const { return x_; } int Y() const { return y_; } Point Move(int ox, int oy) const { return Point(x_ + ox, y_ + oy); } private: const int x_, y_; };
class Point { public: Point(int x, int y) : x_(x), y_(y) {} Point& operator=(const Point&) = delete; int X() const { return x_; } int Y() const { return y_; } Point Move(int ox, int oy) const { return Point(x_ + ox, y_ + oy); } private: const int x_, y_; };
• Стабильное состояние • Невозможно сломать • Экономит время на синхронизации • Удобно для многопоточной среды
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Поиск
Справочник
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Map designed by Nicholas Menghini from the thenounproject.com
Поиск
Справочник
Карта
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Map designed by Nicholas Menghini from the thenounproject.com
Folder Tree designed by Juan Pablo Bravo from the thenounproject.com
Поиск
Справочник
Карта
VFS
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Map designed by Nicholas Menghini from the thenounproject.com
Folder Tree designed by Juan Pablo Bravo from the thenounproject.com
Поиск
Справочник
Карта
VFS
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Map designed by Nicholas Menghini from the thenounproject.com
Folder Tree designed by Juan Pablo Bravo from the thenounproject.com
Поиск
Справочник
Карта
Обновления
VFS
Magnifying Glass designed by Karl Schaeffler from the thenounproject.com
Book designed by Olivier Guin from the thenounproject.com
Map designed by Nicholas Menghini from the thenounproject.com
Folder Tree designed by Juan Pablo Bravo from the thenounproject.com
Поиск
Справочник
Карта
Обновления
VFS
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
1
typedef std::shared_ptr<const IFile> IFilePtr; typedef std::shared_ptr<const IDir> IDirPtr;
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
1 Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
typedef std::shared_ptr<const IFile> IFilePtr; typedef std::shared_ptr<const IDir> IDirPtr;
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
1 Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
1 Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
typedef std::shared_ptr<const VfsNode> VfsNodePtr;
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
1 Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
typedef std::shared_ptr<const VfsNode> VfsNodePtr;
IDir
File(string): IFilePtr Dir(string): IDirPtr
VfsNode
Create(path, dir): VfsNodePtr AddDir(path, dir): VfsNodePtr RemoveDir(path): VfsNodePtr
0..*
Path
Head(): string Tail(): Path
Vfs
1 Root(): IDirPtr AddDir(path, dir) RemoveDir(path)
typedef std::shared_ptr<const VfsNode> VfsNodePtr;
class Vfs { public: IDirPtr Root() const; void AddDir(const Path& path, IDirPtr dir); void RemoveDir(const Path& path); };
class Vfs { public: IDirPtr Root() const; void AddDir(const Path& path, IDirPtr dir); void RemoveDir(const Path& path); private: std::mutex update_mtx_; std::atomic<VfsNodePtr> root_; };
void Vfs::AddDir(const Path& path, IDirPtr dir) { std::lock_guard<std::mutex> lock(update_mtx_); const VfsNodePtr root = root_; root_ = root ? root->AddDir(path, std::move(dir)) : VfsNode::Create(path, std::move(dir)); }
std::mutex update_mtx_; std::atomic<VfsNodePtr> root_;
void Vfs::RemoveDir(const Path& path) { std::lock_guard<std::mutex> lock(update_mtx_); if (const VfsNodePtr root = root_) { root_ = root->RemoveDir(path); } }
std::mutex update_mtx_; std::atomic<VfsNodePtr> root_;
IDirPtr Vfs::Root() const { return root_.load(); }
std::mutex update_mtx_; std::atomic<VfsNodePtr> root_;
Кудрин Игорь [email protected]
Mail designed by Andy Fuchs from the thenounproject.com
struct IFile; typedef std::shared_ptr<const IFile> IFilePtr; struct IDir; typedef std::shared_ptr<const IDir> IDirPtr; struct IDir { virtual IFilePtr File(const std::string& name) const = 0; virtual IDirPtr Dir(const std::string& name) const = 0; };
Бонус: IDir
class VfsNode : public IDir, public std::enable_shared_from_this<VfsNode> { typedef std::unordered_map<std::string, VfsNodePtr> ChildrenMap; const IDirPtr dir_; const ChildrenMap children_; public: explicit VfsNode(IDirPtr dir) : dir_(std::move(dir)), children_() {} explicit VfsNode(ChildrenMap children) : dir_(), children_(std::move(children)) {} };
Бонус: VfsNode
VfsNodePtr VfsNode::Create(const Path& path, IDirPtr dir) { if (path.Head().empty()) { return std::make_shared<VfsNode>(std::move(dir)); } else { ChildrenMap children = { { path.Head(), Create(path.Tail(), std::move(dir)) } }; return std::make_shared<VfsNode>(std::move(children)); } }
Бонус: VfsNode
VfsNodePtr VfsNode::AddDir(const Path& path, IDirPtr dir) const { if (path.Head().empty()) { return std::make_shared<VfsNode>(std::move(dir)); } ChildrenMap children = children_; VfsNodePtr& node = children[path.Head()]; node = (nullptr != node) ? node->AddDir(path.Tail(), std::move(dir)) : VfsNode::Create(path.Tail(), std::move(dir)); return std::make_shared<VfsNode>(std::move(children)); }
Бонус: VfsNode
VfsNodePtr VfsNode::RemoveDir(const Path& path) const { if (path.Head().empty()) return VfsNodePtr(); ChildrenMap children = children_; const auto it = children.find(path.Head()); if (it == children.end()) return shared_from_this(); VfsNodePtr new_child_node = it->second->RemoveDir(path.Tail()); if (new_child_node == it->second) return shared_from_this(); if (new_child_node) it->second.swap(new_child_node); else { children.erase(it); if (children.empty()) return VfsNodePtr(); } return std::make_shared<VfsNode>(std::move(children)); }
Бонус: VfsNode