C++: Performance Optimization

Last updated: 2026-08-26

In lesson 48, we learned about C++17/20 new features.

Now, we'll learn about performance optimization — making C++ programs run faster.

C++'s advantage is performance, but using it well is not easy.


1. Performance Optimization Overview

(1) 1.1 Why Optimize?

Principles:

  1. Don't optimize prematurely (Premature Optimization)
  2. Measure first, then optimize
  3. Optimize the algorithm first, then the code

(2) 1.2 Performance Bottlenecks

Bottleneck Proportion
Algorithm 70%
Memory access 20%
Other 10%

Conclusion: Optimizing the algorithm is more important than optimizing the code.



2. Memory Alignment

(1) 2.1 What Is Memory Alignment?

Memory alignment means that data is stored at memory addresses that are multiples of a certain value (usually a power of 2).

Why is it important?


(2) 2.2 Example: Impact of memory alignment (Difficulty ⭐⭐)

▶ Example 1: Object-oriented programming demo (Difficulty ⭐)

CPP
#include <iostream>

struct BadAlignment {
 char c; // 1 byte
 int i; // 4 bytes (may be aligned to offset 4)
};

struct GoodAlignment {
 int i; // 4 bytes
 char c; // 1 byte
};

int main() {
 std::cout << "Bad: " << sizeof(BadAlignment) << " bytes" << std::endl;
 std::cout << "Good: " << sizeof(GoodAlignment) << " bytes" << std::endl;
 
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Bad: 8 bytes
Good: 8 bytes

Possible run result:

TEXT 📖 Display only
Bad: 8 bytes
Good: 8 bytes

💡 Tip:



3. Cache Friendliness

(1) 3.1 CPU Cache

CPU cache is 100 times faster than main memory.

Optimization principles:

  1. Principle of locality: Access adjacent memory
  2. Sequential access: Faster than random access
  3. Avoid cache misses: Minimize access to non-contiguous memory

(2) 3.2 Example: Row-major vs column-major order (Difficulty ⭐⭐⭐)

CPP
#include <iostream>
### ▶ Example 2: STL container usage (Difficulty ⭐)

#include <vector>
#include <chrono>

int main() {
 const int N = 1000;
 std::vector<std::vector<int>> matrix(N, std::vector<int>(N));
 
 // Row-major (cache friendly)
 auto start = std::chrono::high_resolution_clock::now();
 for (int i = 0; i < N; i++) {
 for (int j = 0; j < N; j++) {
 matrix[i][j] = 1;
 }
 }
 auto end = std::chrono::high_resolution_clock::now();
 auto row_time = std::chrono::duration<double>(end - start).count();
 
 // Column-major (cache unfriendly)
 start = std::chrono::high_resolution_clock::now();
 for (int j = 0; j < N; j++) {
 for (int i = 0; i < N; i++) {
 matrix[i][j] = 1;
 }
 }
 end = std::chrono::high_resolution_clock::now();
 auto col_time = std::chrono::duration<double>(end - start).count();
 
 std::cout << "Row-major time: " << row_time << " seconds" << std::endl;
 std::cout << "Column-major time: " << col_time << " seconds" << std::endl;
 
 return 0;
}

Output:

TEXT 📖 Display only
Row-major time: 0.001 seconds
Column-major time: 0.003 seconds


4. Compiler Optimization

(1) 4.1 Optimization Levels

Level Flag Description
O0 None No optimization (for debugging)
O1 -O1 Basic optimization
O2 -O2 Recommended (balanced)
O3 -O3 Aggressive optimization
Os -Os Optimize for size

(2) 4.2 Example: Compiler optimization effect (Difficulty ⭐)

CPP
#include <iostream>

int main() {
 int sum = 0;
 for (int i = 0; i < 1000000; i++) {
 sum += i;
 }
 std::cout << sum << std::endl;
 
 return 0;
}

Output:

TEXT 📖 Display only
499999500000

Compilation:

BASH
g++ -O0 main.cpp # Slow
g++ -O2 main.cpp # Fast (compiler may compute the result directly)


5. Profiling Tools

(1) 5.1 Common Tools

Tool Platform Description
gprof Linux GCC profiler
perf Linux Linux performance analysis tool
Valgrind Cross-platform Memory analysis
Visual Studio Profiler Windows Built into VS

(2) 5.2 Example: Measuring time with chrono (Difficulty ⭐)

CPP
#include <iostream>
#include <chrono>

int main() {
 auto start = std::chrono::high_resolution_clock::now();
 
 // Code to measure
 long sum = 0;
 for (int i = 0; i < 100000000; i++) {
 sum += i;
 }
 
 auto end = std::chrono::high_resolution_clock::now();
 auto duration = std::chrono::duration<double>(end - start).count();
 
 std::cout << "Time elapsed: " << duration << " seconds" << std::endl;
 
 return 0;
}

Output:

TEXT 📖 Display only
Time elapsed: 0.05 seconds


6. Optimization Techniques Summary

(1) 6.1 Code Level

Technique Description
Use move semantics Reduce copies
Use emplace_back Avoid temporary objects
Use reserve Reduce vector reallocation
Use unordered_map Hash table, O(1) lookup

(2) 6.2 Algorithm Level

Technique Description
Choose the right data structure vector vs list vs map
Use appropriate algorithms sort vs partial_sort
Avoid unnecessary copies Use references, move

▶ Example 3: Pass by value vs pass by reference performance comparison (Difficulty ⭐)

CPP
#include <iostream>
#include <vector>
#include <chrono>

struct BigData {
    std::vector<int> data;
    BigData() : data(10000, 0) {}
};

// Pass by value (copy)
void processByValue(BigData d) {
    (void)d;
}

// Pass by reference (no copy)
void processByRef(const BigData& d) {
    (void)d;
}

int main() {
    BigData big;

    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000; i++) {
        processByValue(big);
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Pass by value time: " << std::chrono::duration<double>(end - start).count() << " seconds" << std::endl;

    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000; i++) {
        processByRef(big);
    }
    end = std::chrono::high_resolution_clock::now();
    std::cout << "Pass by reference time: " << std::chrono::duration<double>(end - start).count() << " seconds" << std::endl;

    return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Pass by value time: 0.15 seconds
Pass by reference time: 0.001 seconds

❓ FAQ

Q Is optimization always effective?
A Not necessarily. Measure first, find the bottleneck, then optimize.

Q Is C++ always faster than Python?
A Not necessarily. If the algorithm is the same, C++ is usually faster. But with a poor algorithm, C++ can also be slow.

Q How do I determine where the bottleneck is?
A Use a profiler.

📖 Summary

Key Point Summary
Memory alignment Reduce padding
Cache friendliness Sequential access, locality
Compiler optimization -O2 recommended
Profiling Measure first, then optimize
Optimization techniques Move semantics, emplace_back

📝 Exercises

  1. Basic (Difficulty ⭐): Store 100,000 integers using both vector and list, and compare the time difference for tail insertion and random access.

  2. Intermediate (Difficulty ⭐⭐): Test the performance difference between pass by value and pass by reference. Write a function that processes a large struct (containing vector<int>(10000)), measuring the time for both value passing and const reference passing.

  3. Challenge (Difficulty ⭐⭐⭐): Use std::chrono high-precision timing to compare the performance differences between a for loop, STL for_each, and range-based for when traversing. Analyze the results.



Next lesson: Unit Testing (#50)

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏