C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
249: std::chrono for Time and Durations
I've seen this happen in almost every code review I've done for junior devs moving from C or Python to C++: they treat time as a simple number. They'll create an int or a double called elapsed_time, assume it's in milliseconds, and then spend the next three hours debugging a production crash because one library returned seconds and another returned microseconds.
Stop treating time as a raw integer
The biggest misconception about std::chrono is that it's just a "clunky" way to get the current time. In reality, it's a type-safety system designed specifically to stop you from accidentally adding "5 apples" to "10 oranges"—or in this case, adding 5 seconds to 10 milliseconds.
Look at this common mistake:
auto start = std::chrono::steady_clock::now();
// ... some heavy work ...
auto end = std::chrono::steady_clock::now();
// WRONG: This won't even compile.
auto duration = end - start;
int ms = duration;
You'll get a mountain of template error messages. Why? Because duration isn't an integer; it's a std::chrono::duration object. C++ refuses to implicitly convert a typed duration into a raw number because that's exactly where the "is this seconds or milliseconds?" bugs come from. I used to fight this when I first learned it, but once you realize the type system is actually protecting you from yourself, it becomes a superpower.
Distinguishing Time Points from Durations
To use chrono effectively, you have to keep two concepts strictly separate in your head: time_point and duration.
- time_point: A specific moment in time (like "Tuesday at 2:00 PM"). In code, this is usually what you get from
std::chrono::steady_clock::now(). - duration: A span of time (like "42 milliseconds"). This is the result of subtracting one
time_pointfrom another.
If you want to represent a specific amount of time, use the built-in aliases like std::chrono::milliseconds or std::chrono::seconds. They make the code read like English:
#include <chrono>
#include <iostream>
#include <thread>
void wait_for_server() {
using namespace std::chrono_literals; // Enables suffixes like 500ms
std::cout <"Waiting for response..."< std::endl;
// We pass a duration here
std::this_thread::sleep_for(500ms);
std::cout <"Done!"< std::endl;
}
Handling precision with duration_cast
Here is where things get a bit annoying. C++ allows implicit conversions if you are moving from a coarse unit to a fine unit (e.g., seconds to milliseconds), because there's no loss of data. But it forbids them in the other direction.
If you have a duration in nanoseconds and you want to store it as milliseconds, you're losing precision. C++ forces you to be explicit about this using std::chrono::duration_cast. I consider this a "sanity check" for the developer.
Here is the professional way to time a block of code:
auto start = std::chrono::steady_clock::now();
// Simulate work
std::this_thread::sleep_for(std::chrono::milliseconds(123));
auto end = std::chrono::steady_clock::now();
// Subtracting two time_points gives us a duration
auto diff = end - start;
// Explicitly cast to the unit you actually want to print/use
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(diff);
std::cout < "Elapsed time: " < ms.count() < "ms" < std::endl;
Note the .count() member function. That is the only place where the type-safe duration turns back into a raw number. Use it only at the very last second—usually right when you're printing to the console or saving to a database.
📋 Practical Task
Build a High-Precision Ability Cooldown Tracker
In game development, you often need to ensure an ability (like a "Fireball") cannot be used more than once every X milliseconds. Your task is to implement a CooldownManager class that handles this using std::chrono.
Requirements:
- Create a class
CooldownManager. - It should have a constructor that takes a
std::chrono::millisecondsvalue to set the cooldown period. - Implement a method
bool can_use_ability().- It returns
trueif the cooldown has expired and updates the "last used" timestamp to the current time. - It returns
falseif the ability is still on cooldown.
- It returns
- Use
std::chrono::steady_clockto ensure the timer isn't affected by the user changing the system wall-clock time.
Test Case: Initialize the manager with a 500ms cooldown. Call can_use_ability() once (should be true), call it again immediately (should be false), sleep for 600ms, and call it again (should be true).
There are no comments for now.