Experienced C++ Interview Questions

What is a data race in C++ and how do you prevent it?

A data race is two or more threads reading and writing the same variable at the same time with no lock. It is undefined behavior. Prevent it with:

  • std::mutex and std::lock_guard or std::scoped_lock.
  • std::atomic<T> for simple counters and flags.
  • Not sharing data: give each thread its own data.
#include <atomic>
#include <iostream>
#include <thread>
#include <vector>

int main() {
    std::atomic<int> counter{0};
    std::vector<std::thread> threads;
    for (int t = 0; t < 4; t++) {
        threads.emplace_back([&counter] { for (int i = 0; i < 50000; i++) counter++; });
    }
    for (auto& t : threads) t.join();
    std::cout << counter << '\n';
}
Output

200000

Find races with ThreadSanitizer: g++ -fsanitize=thread. See C++ Multithreading.

What is copy elision and RVO in C++?

When a function returns an object, the compiler can build it directly in the place of the caller, with no copy and no move. This is copy elision. Since C++17 it is guaranteed when you return a temporary (a prvalue). With a named local variable (NRVO) it is allowed, and most compilers do it.

#include <iostream>

struct Noisy {
    Noisy() { std::cout << "construct\n"; }
    Noisy(const Noisy&) { std::cout << "copy\n"; }
    Noisy(Noisy&&) noexcept { std::cout << "move\n"; }
};

Noisy make() { return Noisy(); }                 // guaranteed: no copy, no move

int main() {
    Noisy n = make();
}
Output

construct

So return std::move(local); is a mistake: it can stop the elision. Just write return local;. See Move Semantics.