Lesson content
Read, practise, then check your understanding
Correctness and design come before speed. Give every resource a clear owner, prefer values and RAII, keep scopes small, initialize objects, make invalid states hard to represent, and compile with strong warnings. Use const, constexpr, noexcept, and [[nodiscard]] when they express a real contract.
#include <span>
[[nodiscard]] double average(std::span<const int> values) {
if (values.empty()) return 0.0;
long long sum{};
for (int value : values) sum += value;
return static_cast<double>(sum) / values.size();
}
Separate interfaces from implementation, favor composition, and use standard containers and algorithms. Avoid owning raw pointers, unchecked indexing at trust boundaries, C-style casts, macros where typed alternatives exist, and undefined behavior. Automate formatting, static analysis, unit/integration tests, and sanitizer builds.
Optimize methodically
Define a performance goal, benchmark a representative workload, profile to find the bottleneck, change one thing, then measure again. Algorithmic improvement usually dominates instruction-level tuning. Data layout and locality often matter more than clever syntax; contiguous vectors frequently outperform node-based containers.
Avoid accidental copies with references or moves, but do not sacrifice lifetime safety. Reserve capacity when growth is predictable, batch I/O, and reduce allocation only where profiles show value. Treat concurrency as a scalability tool with overhead, not a universal speedup. Preserve readable code and regression tests around every optimization so future maintainers can verify both result and reason.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.