Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Software Architecture with C++

You're reading from   Software Architecture with C++ Design modern systems using effective architecture concepts, design patterns, and techniques with C++20

Arrow left icon
Product type Paperback
Published in Apr 2021
Publisher Packt
ISBN-13 9781838554590
Length 540 pages
Edition 1st Edition
Languages
Arrow right icon
Authors (2):
Arrow left icon
Adrian Ostrowski Adrian Ostrowski
Author Profile Icon Adrian Ostrowski
Adrian Ostrowski
Piotr Gaczkowski Piotr Gaczkowski
Author Profile Icon Piotr Gaczkowski
Piotr Gaczkowski
Arrow right icon
View More author details
Toc

Table of Contents (24) Chapters Close

Preface 1. Section 1: Concepts and Components of Software Architecture
2. Importance of Software Architecture and Principles of Great Design FREE CHAPTER 3. Architectural Styles 4. Functional and Nonfunctional Requirements 5. Section 2: The Design and Development of C++ Software
6. Architectural and System Design 7. Leveraging C++ Language Features 8. Design Patterns and C++ 9. Building and Packaging 10. Section 3: Architectural Quality Attributes
11. Writing Testable Code 12. Continuous Integration and Continuous Deployment 13. Security in Code and Deployment 14. Performance 15. Section 4: Cloud-Native Design Principles
16. Service-Oriented Architecture 17. Designing Microservices 18. Containers 19. Cloud-Native Design 20. Assessments 21. About Packt 22. Other Books You May Enjoy Appendix A

The philosophy of C++

Let's now move closer to the programming language we'll be using the most throughout this book. C++ is a multi-paradigm language that has been around for a few decades now. During the years since its inception, it has changed a lot. When C++11 came out, Bjarne Stroustrup, the creator of the language, said that it felt like a completely new language. The release of C++20 marks another milestone in the evolution of this beast, bringing a similar revolution to how we write code. One thing, however, stayed the same during all those years: the language's philosophy.

In short, it can be summarized by three rules:

  • There should be no language beneath C++ (except assembly).
  • You only pay for what you use.
  • Offer high-level abstractions at low cost (there's a strong aim for zero-cost).

Not paying for what you don't use means that, for example, if you want to have your data member created on the stack, you can. Many languages allocate their objects on the heap, but it's not necessary for C++. Allocating on the heap has some cost to it – probably your allocator will have to lock a mutex for this, which can be a big burden in some types of applications. The good part is you can easily allocate variables without dynamically allocating memory each time pretty easily.

High-level abstractions are what differentiate C++ from lower-level languages such as C or assembly. They allow for expressing ideas and intent directly in the source code, which plays great with the language's type safety. Consider the following code snippet:

struct Duration {
int millis_;
};

void example() {
auto d = Duration{};
d.millis_ = 100;

auto timeout = 1; // second
d.millis_ = timeout; // ouch, we meant 1000 millis but assigned just 1
}

A much better idea would be to leverage the type-safety features offered by the language:

#include <chrono>

using namespace std::literals::chrono_literals;

struct Duration {
std::chrono::milliseconds millis_;
};

void example() {
auto d = Duration{};
// d.millis_ = 100; // compilation error, as 100 could mean anything
d.millis_ = 100ms; // okay

auto timeout = 1s; // or std::chrono::seconds(1);
d.millis_ =
timeout; // okay, converted automatically to milliseconds
}

The preceding abstraction can save us from mistakes and doesn't cost us anything while doing so; the assembly generated would be the same as for the first example. That's why it's called a zero-cost abstraction. Sometimes C++ allows us to use abstractions that actually result in better code than if they were not used. One example of a language feature that, when used, could often result in such benefit is coroutines from C++20.

Another great set of abstractions, offered by the standard library, are algorithms. Which of the following code snippets do you think is easier to read and easier to prove bug-free? Which expresses the intent better?

// Approach #1
int count_dots(const char *str, std::size_t len) {
int count = 0;
for (std::size_t i = 0; i < len; ++i) {
if (str[i] == '.') count++;
}
return count;
}

// Approach #2
int count_dots(std::string_view str) {
return std::count(std::begin(str), std::end(str), '.');
}

Okay, the second function has a different interface, but even it if was to stay the same, we could just create std::string_view from the pointer and the length. Since it's such a lightweight type, it should be optimized away by your compiler.

Using higher-level abstractions leads to simpler, more maintainable code. The C++ language has strived to provide zero-cost abstractions since its inception, so build upon that instead of redesigning the wheel using lower levels of abstraction.

Speaking of simple and maintainable code, the next section introduces some rules and heuristics that are invaluable on the path to writing such code.

You have been reading a chapter from
Software Architecture with C++
Published in: Apr 2021
Publisher: Packt
ISBN-13: 9781838554590
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime