0% found this document useful (0 votes)
164 views36 pages

Key C++ Practice Problems (And Solutions) From Beginner To Senior Level - CodeSignal

Uploaded by

badoublejay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
164 views36 pages

Key C++ Practice Problems (And Solutions) From Beginner To Senior Level - CodeSignal

Uploaded by

badoublejay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

Level up your engineering team with CodeSignal Develop LEARN MORE →

INTERVIEW PREP

Key C++ practice problems


(and solutions) from beginner
to senior level
TEAM CODESIGNAL

BACK TO BLOG

Not sure what to practice?


In this guide, we delve into a wide array of C++ problems, ranging from
fundamental syntax and basic data structures for beginners, to advanced concepts
like object-oriented programming (OOP) and efficient memory management for
experienced developers. Each problem is accompanied by a detailed solution and
an explanation to aid in understanding the solution and to deepen your grasp of
the underlying concepts. Whether you’re starting your journey in C++ or looking to
refine your expertise, this guide serves as a valuable resource to navigate through
the intricacies of one of the most powerful programming languages.
Evaluating your current skill level in C++ is crucial for effective learning. We
recommend starting with basic problems and gradually progressing to more
complex ones, allowing you to accurately gauge your understanding and identify
areas needing improvement. Setting clear goals is essential, whether it’s mastering
specific features of C++ or preparing for a technical interview. Your goals should
align with your professional development objectives and the role you’re
interviewing for—whether that means becoming proficient in writing efficient code
for large-scale applications, or gaining a deep understanding of lower-level C++ for
system-level programming.

To create a structured practice plan, start by allocating regular, focused practice


sessions, prioritize topics based on your goals, and use a variety of resources like
coding challenges, open-source projects, and community forums to enhance your
learning experience. The key to mastering C++ is consistent practice and a
willingness to continually challenge yourself.

Jump to a section
What you will need to get started
How to solve our C++ practice problems for maximum benefit
Essential C++ practice problems (and solutions) for beginners
Language fundamentals and syntax
C++ control structures
Basic I/O operations with C++
Object-oriented programming
Basic data structures
Advanced C++ practice problems (and solutions)
Advanced data structures and algorithms
Memory management
Concurrency and multithreading
Advanced features of C++
Next steps & resources

What you will need to get started


Before diving into practice problems, you’ll need to configure your coding
environment if you haven’t already. You have various options, each with its own
merits and drawbacks. Trying out multiple setups can improve your adaptability,
so take the time to discover which one suits your preferences and workflow best.
We’ll discuss some environment options below.

IDEs
Using fully-featured IDEs for C++ interview preparation provides a comprehensive
environment, integrating editing, building, and debugging seamlessly. The GUI-
based project configuration simplifies the setup, making it easier to manage larger
codebases efficiently. IDEs come with advanced features like code refactoring,
enhancing productivity during interview simulations. However, be mindful of the
potentially steep learning curve associated with complex UIs, and the resource-
intensive nature of IDEs if you haven’t used one before.

Conversely, for more senior engineers and those very comfortable with their IDE,
pay attention to your debugging methods. Many interview platforms don’t have rich
environments for watching variables, compilation warnings, and code completion,
so consider practicing interview questions in a different environment than what
you’re used to so that you’re able to adapt to a few methods of debugging.

Code editor and command line


For interview practice in C++, opting for a code editor like Sublime Text or VS Code
with command-line tools provides flexibility and control. This setup allows
developers to delve into the intricacies of makefiles and the build process, which
can be helpful for beginners learning how compilation works in C++ and how files
interact. While this setup is lightweight and fast, offering a consistent experience
across platforms, be aware that configuring the toolchain and compiler may
require extra effort. The lack of built-in debugging may make it difficult for
beginners that are still learning C++ debugging. Nevertheless, this approach can be
beneficial for honing manual coding and build skills, which are often tested in
interviews.

Online IDEs
For quick, instant coding practice, online IDEs offer immediate accessibility
without the need for setup. They are suitable for short, focused tests and
demonstrations, making them convenient for interview preparation. This helps
emulate many interview situations where you’re coding online with a less-
customized environment. However, be aware of the limitations, such as restricted
features compared to desktop IDEs. The inability to save work locally might be a
drawback if you want to review your code later in another IDE for practice, and
requiring internet access might limit when you can practice.

Libraries and dependencies


When preparing for C++ interviews, having the right libraries accessible simplifies
implementation and allows you to concentrate on core programming concepts.

Fortunately, most standard facilities needed for interview practice come built-in:

Headers like <algorithm>, <vector>, <string> provide collections, utilities


I/O streams using <iostream> and <fstream>
Containers/iterators in <array>, <list>, <map>
Multithreading primitives via <thread>, <mutex>
Built-in smart pointers like std::unique_ptr
These and more ship standard with any C++ compiler so are always available.

While the STL suffices for most fundamental coding challenges, some additional
libraries useful to have handy include:

Boost: For added containers, algorithms, strings, testing


Qt: GUI development and platform abstractions
OpenSSL” Cryptography and secure communication
Libcurl: HTTP and network transfers

Ideally, have these pre-installed and integrated into the dev environment instead
of figuring out during interviews. This removes distractions to stay focused. Most
build systems or Linux package managers make acquiring these straightforward.

How to solve our C++ practice


problems for maximum benefit
Beginning C++ Interview Techniques
In preparation for C++ interviews, some principles apply regardless of your
seniority. Study essentials like OOP concepts of inheritance and polymorphism,
handling exceptions properly with try/catch blocks, leveraging C++11 smart
pointers for automatic memory management, and applying move semantics for
performance. Additionally, become fluent with the Standard Template Library
(STL), including the central vectors, maps, sets, strings, iterators, algorithms for
sorting/searching, and templates for generic programming. Knowing these building
blocks allows for efficiently solving most problems without reinventing built-in
capabilities. Additionally, practice analyzing algorithmic complexity using big-O
notation, as interviewers will often ask for the theoretical efficiency of code
implementations. A solid grasp of big-O allows you to compare the scalability of
different solutions critically to select the most optimal approach.

Beyond honing your proficiency in the language’s fundamentals, familiarize yourself


with the compiler and build process, incorporating tools like Makefiles, as this
knowledge proves invaluable for troubleshooting and optimizing code. The extent
to which you’ll need to master these areas will depend on your experience and
goals.

Advanced C++ Interviewing Techniques


In addition to the general advice outlined above, more senior developers will have
to prepare to effectively use advanced C++ features in their interviews. When
solving these more difficult problems, prioritizing optimizing speed and memory
usage becomes more important as solutions can quickly become complex. As with
more beginner questions, leverage existing STL containers and algorithms before
opting for custom implementations, always considering space-time tradeoffs.
Effective memory management is crucial—manually handle cleanup and freeing
resources when working with custom allocators, and use smart pointers for
automatic management. Ensure constructors and destructors are carefully
managed, emphasizing clear organization for memory lifetimes and ownership
intent.

When encountering questions regarding concurrency, minimize shared mutable


state between threads, use mutex locks judiciously, and prefer condition variables
over busy wait loops for efficiency. Make concurrent code exception-safe when
needed, and stress-test to identify and address race conditions. Additionally,
explore template metaprogramming (TMP) techniques, such as SFINAE
(Substitution Failure Is Not An Error) and type traits, as they can empower you
with tools to create flexible and efficient code. These practices contribute to a
comprehensive understanding of advanced C++ concepts, enhancing your
problem-solving skills and proficiency in the language.

Essential C++ practice problems (and


solutions) for beginners
For introductory C++ interview questions, interview questions often prioritize
evaluating problem decomposition skills, data structure comprehension, and
general coding aptitude over specialized library or language syntax familiarity. That
said, C++ is a difficult language, so mastering the essential language fundamentals
and syntax is the initial key to success. Familiarize yourself with prevalent libraries
and patterns, allowing you to concentrate on solving the interview problem
without struggling with C++ details.

With any language, you’ll need to build a solid foundation in implementing basic
data structures, such as dynamic arrays and stacks, as well as common algorithm
patterns and object-oriented programming principles. This set of beginner-level
and essential questions aims to evaluate your grasp on foundational concepts,
setting the stage for more advanced assessments.

Language fundamentals and syntax


Question 1: Print a custom message
Prompt: Write a C++ program that prompts the user to enter their name and then
prints a greeting message, “Hello, [name]!”.

What skills this question evaluates: This question tests basic input/output
operations and string manipulation in C++. It evaluates the ability to use cin for
input and cout for output.

Solution:

cpp
Copy code
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
cout << "Enter your name: ";
cin >> name;
cout << "Hello, " << name << "!" << endl;
return 0;
}

Explanation of the solution: This solution involves using the iostream library for
input and output operations. The program first declares a string variable name,
then uses cin to read the user’s name and cout to print the greeting. The usage of
<< operator for output and >> for input is fundamental in C++.

Question 2: Sum of two numbers


Prompt: Enhance your program to prompt the user to enter two integers. The
program should then print the sum of these two integers.

What skills this question evaluates: This question builds on the first by adding
arithmetic operations and basic data type handling. It assesses the candidate’s
ability to perform calculations and handle user input.

Solution:

cpp
Copy code
#include <iostream>
using namespace std;
int main() {
int num1, num2;
cout << "Enter two numbers: ";
cin >> num1 >> num2;
cout << "The sum is: " << num1 + num2 << endl;
return 0;
}

Explanation of the solution: This solution introduces integer variables num1 and
num2. The program uses cin to read two integers inputted by the user and
calculates their sum using the + operator. This introduces the concept of
arithmetic operations and multiple data input in C++. The use of cin >> num1 >>
num2 demonstrates how to read multiple inputs in a single line.

C++ control structures


Question 1: Check for an even or odd number
Prompt: Write a C++ program that asks the user to input an integer and then
prints whether the number is even or odd.

What skills this question evaluates: This question tests the understanding of
conditional statements (if-else). It evaluates the ability to use logical expressions
to make decisions in C++.

Solution:

cpp
Copy code
#include <iostream>
using namespace std;
int main() {
int number;
cout << "Enter an integer: ";
cin >> number;
if (number % 2 == 0) {
cout << number << " is even." << endl;
} else {
cout << number << " is odd." << endl;
}
return 0;
}

Explanation of the solution: This solution uses an if-else statement to determine


if a number is even or odd. The % operator is used to find the remainder when the
number is divided by 2. If the remainder is 0, the number is even; otherwise, it’s
odd. This demonstrates basic conditional logic in C++.
Question 2: Counting positive and negative numbers
Prompt: Modify your program to allow the user to enter multiple numbers until a
zero is entered. After zero is entered, the program should print the count of
positive and negative numbers entered.

What skills this question evaluates: This question builds on the previous one by
adding a while loop for repeated input. It assesses the understanding of loops and
conditional statements combined.

Solution:

cpp
Copy code
#include <iostream>
using namespace std;
int main() {
int number, positiveCount = 0, negativeCount = 0;
cout << "Enter numbers (0 to stop): ";
while (cin >> number && number != 0) {
if (number > 0) {
positiveCount++;
} else {
negativeCount++;
}
}
cout << "Positive numbers: " << positiveCount << endl;
cout << "Negative numbers: " << negativeCount << endl;
return 0;
}

Explanation of the solution: In this solution, a while loop is used to continuously


read numbers from the user until zero is entered. Within the loop, an if-else
statement increments either positiveCount or negativeCount based on whether
the number is positive or negative. This question demonstrates the use of loops
for repetitive tasks and conditional statements for decision-making in C++.

Basic I/O operations with C++


Question 1: User-inputted string reversal
Prompt: Write a C++ program that prompts the user to enter a string, and then
prints the reverse of the string.

What skills this question evaluates: This question tests the candidate’s ability to
handle input/output operations and basic string manipulation. It assesses how to
use standard input to receive a string and then process it to produce the reversed
version.

Solution:

cpp
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string input;
cout << "Enter a string: ";
getline(cin, input);
reverse(input.begin(), input.end());
cout << "Reversed string: " << input << endl;
return 0;
}

Explanation of the solution: The program reads a string from the user using
`getline` to handle potentially spaced input. It then utilizes the `reverse` function
from the standard `<algorithm>` library to reverse the string in-place. This
solution demonstrates basic string handling and the use of the standard library for
string manipulation.

Question 2: Writing and reading a string to/from a file


Prompt: Modify your program to write the reversed string to a file named
“output.txt”. Then, read the string back from the file and print it to the console.

What skills this question evaluates: This question adds basic file handling to the
previous skills of string manipulation and I/O operations. It evaluates the ability to
write to and read from a file in C++.

Solution:

cpp
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string input;
cout << "Enter a string: ";
getline(cin, input);
reverse(input.begin(), input.end());
// Write to file
ofstream outFile("output.txt");
outFile << input;
outFile.close();
// Read from file and print
string fileContent;
ifstream inFile("output.txt");
getline(inFile, fileContent);
cout << "String from file: " << fileContent << endl;
inFile.close();
return 0;
}

Explanation of the solution: This solution extends the previous string reversal
program to include file I/O operations. The reversed string is written to
“output.txt” using an `ofstream` object. The program then creates an `ifstream`
object to read the content back from the file and prints it to the console. This
demonstrates how to handle basic file operations in C++, including writing to and
reading from files.

Object-oriented programming
Question 1: Creating a basic class
Prompt: Define a C++ class named `Car` with private member variables for
`brand` (string), `model` (string), and `year` (integer). Include public member
functions to set and get the values of these variables.

What skills this question evaluates: This question assesses understanding of basic
class creation, encapsulation, and the use of public member functions for
accessing private data. It focuses on the fundamental principles of object-oriented
programming in C++.

Solution:

cpp
#include <iostream>
#include <string>
using namespace std;
class Car {
private:
string brand;
string model;
int year;
public:
void setBrand(const string &b) {
brand = b;
}
void setModel(const string &m) {
model = m;
}
void setYear(int y) {
year = y;
}
string getBrand() const {
return brand;
}
string getModel() const {
return model;
}
int getYear() const {
return year;
}
};
int main() {
Car myCar;
myCar.setBrand("Toyota");
myCar.setModel("Corolla");
myCar.setYear(2020);
cout << "Car Details: " << myCar.getBrand() << " " <<
myCar.getModel() << " " << myCar.getYear() << endl;
return 0;
}

Explanation of the solution: The `Car` class is defined with private member
variables (`brand`, `model`, `year`) and public methods (`setBrand`, `setModel`,
`setYear`, `getBrand`, `getModel`, `getYear`) for setting and getting these
variables. This encapsulates the data and provides controlled access to it. The
`main` function demonstrates creating an instance of `Car` and using its
methods.

Question 2: Inheritance and polymorphism


Prompt: Extend the `Car` class by creating a subclass named `ElectricCar` that
includes an additional private member variable for `batteryRange` (integer) and
corresponding public functions. Demonstrate polymorphism by creating a function
that takes a `Car` object and prints its details.

This question tests understanding of inheritance and polymorphism. It evaluates


the ability to extend a base class and use polymorphic behavior to work with
objects of both the base and derived classes.

Solution:

cpp
#include <iostream>
#include <string>
using namespace std;
class Car {
// ... (same as above)
};
class ElectricCar : public Car {
private:
int batteryRange;
public:
void setBatteryRange(int range) {
batteryRange = range;
}
int getBatteryRange() const {
return batteryRange;
}
};
void printCarDetails(const Car &car) {
cout << "Car Details: " << car.getBrand() << " " <<
car.getModel() << " " << car.getYear() << endl;
}
int main() {
ElectricCar myElectricCar;
myElectricCar.setBrand("Tesla");
myElectricCar.setModel("Model S");
myElectricCar.setYear(2022);
myElectricCar.setBatteryRange(400);
printCarDetails(myElectricCar);
return 0;
}

Explanation of the solution: The `ElectricCar` class is a subclass of `Car` and


includes an additional property `batteryRange`. The `printCarDetails` function
takes a `Car` object as a parameter, demonstrating polymorphism by also
accepting objects of the `ElectricCar` subclass. In `main`, an `ElectricCar` object
is created, its properties are set, and it is passed to `printCarDetails`. This
showcases inheritance by extending the `Car` class and polymorphism through
the use of a function accepting objects of both the base and derived class.

Basic data structures


Question 1: Implementing a dynamic array
Prompt: Write a C++ class `DynamicArray` that mimics the behavior of a
dynamically resizable array. It should start with a capacity of 1 and double in size
when needed. Implement methods `add(int item)` to add an item to the array and
`get(int index)` to retrieve an item by index.

What skills this question evaluates: This question assesses understanding of


dynamic memory allocation and array resizing, fundamental concepts in managing
data structures. It tests the candidate’s ability to implement basic operations like
adding items and accessing them.

Solution:

cpp
#include <iostream>
#include <cassert>
using namespace std;
class DynamicArray {
private:
int* data;
int size;
int capacity;
void resize() {
capacity *= 2;
int* newData = new int[capacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
delete[] data;
data = newData;
}
public:
DynamicArray() : size(0), capacity(1), data(new
int[capacity]) {}
~DynamicArray() {
delete[] data;
}
void add(int item) {
if (size == capacity) {
resize();
}
data[size++] = item;
}
int get(int index) {
assert(index >= 0 && index < size);
return data[index];
}
};
int main() {
DynamicArray arr;
arr.add(5);
arr.add(10);
cout << "Element at index 0: " << arr.get(0) << endl;
cout << "Element at index 1: " << arr.get(1) << endl;
return 0;
}

Explanation of the solution: The `DynamicArray` class uses a dynamic array


`data` to store integers. It automatically resizes (doubles its capacity) when
needed. The `add` method inserts an item, and `get` retrieves an item at a given
index, with an `assert` statement ensuring the index is valid. The constructor
initializes the array, and the destructor releases the allocated memory.

Question 2: Implementing a stack


Prompt: Based on your `DynamicArray` class, implement a class `Stack` that
supports push, pop, and top operations. Ensure that `pop` and `top` handle the
case when the stack is empty.

What skills this question evaluates: This question tests the ability to use existing
data structures (like the dynamic array) to implement another data structure
(stack). It evaluates understanding of stack operations and error handling in C++.

Solution:

cpp
#include <iostream>
#include <cassert>
using namespace std;
class Stack {
private:
DynamicArray arr;
public:
void push(int item) {
arr.add(item);
}
int pop() {
assert(!isEmpty());
return arr.get(--arr.size);
}
int top() {
assert(!isEmpty());
return arr.get(arr.size - 1);
}
bool isEmpty() {
return arr.size == 0;
}
};
int main() {
Stack stack;
stack.push(10);
stack.push(20);
cout << "Top element: " << stack.top() << endl;
cout << "Popped element: " << stack.pop() << endl;
cout << "New top element: " << stack.top() << endl;
return 0;
}

Explanation of the solution: The `Stack` class uses an instance of `DynamicArray`


to manage its elements. The `push` operation adds an element to the stack, while
`pop` removes and returns the top element. The `top` operation returns the top
element without removing it. Both `pop` and `top` include assertions to check
that the stack is not empty before attempting to access elements. This solution
demonstrates how to build a stack using an underlying dynamic array structure
and includes basic error handling.
Advanced C++ practice problems (and
solutions)
C++ is a complex language, and it requires time and effort to master. While you
may be well-versed in some advanced concepts as a senior programmer, others
may be less familiar to you. Strengthen your expertise in the areas you know
thoroughly to demonstrate your skills and proficiency. Additionally, build a
foundation in other concepts to highlight your versatility and adaptability.

As a senior C++ developer, the expectations go beyond writing functional code;


comprehensive knowledge of software design principles becomes crucial. Senior-
level interviews delve into more complex paradigms like memory management,
multithreading, and optimization strategies, emphasizing scalable and
maintainable solutions. Use the following practice problems to recognize your
areas of strength. After completing them, work on improving your code and
exploring alternate solutions to problems so that you are prepared for a variety of
challenges.

Advanced data structures and algorithms


Question 1: Implementing a Binary Search Tree (BST)
Prompt: Write a C++ class `BinarySearchTree` that implements a basic binary
search tree. The class should have methods to insert a new key, `insert(int key)`,
and to check if a key exists in the tree, `search(int key)`.

What skills this question evaluates: This question assesses understanding of


binary search trees, a fundamental data structure in computer science. It
evaluates the ability to implement key operations like insertion and search, which
require recursive thinking and an understanding of tree traversal.

Solution:

cpp
#include <iostream>
using namespace std;
class Node {
public:
int key;
Node *left, *right;
Node(int item) : key(item), left(nullptr), right(nullptr) {}
};
class BinarySearchTree {
private:
Node* root;
Node* insertRec(Node* root, int key) {
if (root == nullptr) {
return new Node(key);
}
if (key < root->key) {
root->left = insertRec(root->left, key);
} else {
root->right = insertRec(root->right, key);
}
return root;
}
bool searchRec(Node* root, int key) {
if (root == nullptr) {
return false;
}
if (root->key == key) {
return true;
}
return key < root->key ? searchRec(root->left, key) :
searchRec(root->right, key);
}
public:
BinarySearchTree() : root(nullptr) {}
void insert(int key) {
root = insertRec(root, key);
}
bool search(int key) {
return searchRec(root, key);
}
};
int main() {
BinarySearchTree bst;
bst.insert(10);
bst.insert(5);
bst.insert(15);
cout << "Is 10 in BST? " << (bst.search(10) ? "Yes" : "No")
<< endl;
cout << "Is 20 in BST? " << (bst.search(20) ? "Yes" : "No")
<< endl;
return 0;
}

Explanation of the solution: The `BinarySearchTree` class uses a nested `Node`


class to represent each node in the tree. The `insert` method adds a new key to
the tree, while `search` checks for the existence of a key. Both methods use
private recursive helper functions (`insertRec`, `searchRec`) to traverse the tree.

Question 2: Depth-First Search (DFS) in a graph


Prompt: Implement a graph represented as an adjacency list and perform a
depth-first search (DFS) from a given starting node. Write a function `DFS(int
startNode)` that prints the nodes visited during the search.

What skills this question evaluates: This question tests understanding of graph
data structures and depth-first search, an important algorithm in graph theory. It
assesses the ability to implement graphs and traverse them using recursive or
stack-based approaches.

Solution:

cpp
#include <iostream>
#include <list>
#include <vector>
using namespace std;
class Graph {
private:
int numVertices;
list<int> *adjLists;
vector<bool> visited;
void DFSUtil(int vertex) {
visited[vertex] = true;
cout << vertex << " ";
for (int adj : adjLists[vertex]) {
if (!visited[adj]) {
DFSUtil(adj);
}
}
}
public:
Graph(int vertices) : numVertices(vertices), adjLists(new
list<int>[vertices]), visited(vertices, false) {}
void addEdge(int src, int dest) {
adjLists[src].push_back(dest);
}
void DFS(int startNode) {
fill(visited.begin(), visited.end(), false);
DFSUtil(startNode);
}
};
int main() {
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
cout << "Depth First Traversal starting from vertex 2:" <<
endl;
g.DFS(2);
return 0;
}

Explanation of the solution: The `Graph` class uses an adjacency list for
representing the graph and a `visited` vector to track visited nodes. The
`addEdge` method adds edges to the graph. The `DFS` method initializes the
`visited` vector and calls `DFSUtil`, a private method that performs recursive
depth-first traversal from the specified node, printing each visited node. This
solution demonstrates the implementation of a graph and a fundamental graph
traversal algorithm.

Memory management
Question 1: Implementing a smart pointer
Prompt: Write a template class `SmartPointer` that mimics the behavior of a
smart pointer. The class should be able to hold a pointer of any type and should
release the memory when it is no longer in use (i.e., implement basic reference
counting).

What skills this question evaluates: This question assesses the understanding of
dynamic memory management and the concept of smart pointers in C++,
particularly the implementation of reference counting to manage memory
automatically.

Solution:

cpp
#include <iostream>
using namespace std;
template <typename T>
class SmartPointer {
private:
T* ptr;
unsigned* count;
public:
SmartPointer(T* p = nullptr) : ptr(p), count(new
unsigned(1)) {}
SmartPointer(const SmartPointer<T>& sp) : ptr(sp.ptr),
count(sp.count) {
(*count)++;
}
SmartPointer<T>& operator=(const SmartPointer<T>& sp) {
if (this != &sp) {
if (--(*count) == 0) {
delete ptr;
delete count;
}
ptr = sp.ptr;
count = sp.count;
(*count)++;
}
return *this;
}
~SmartPointer() {
if (--(*count) == 0) {
delete ptr;
delete count;
}
}
T& operator*() {
return *ptr;
}
};
int main() {
SmartPointer<int> sp1(new int(10));
SmartPointer<int> sp2 = sp1;
cout << "Value: " << *sp2 << endl;
return 0;
}

Explanation of the solution: The `SmartPointer` template class handles a pointer


and a reference count. The constructor initializes the pointer and the reference
count. The copy constructor and copy assignment operator manage the reference
count, increasing it when a new reference is created and decreasing it when a
reference is destroyed or changed. If the count reaches zero, the memory is
released. This ensures that memory is automatically managed and freed when no
longer needed, demonstrating basic principles of smart pointers.

Question 2: Custom memory allocator


Prompt: Create a custom memory allocator class `CustomAllocator` that allocates
memory for an array of a specified type but does not construct the objects.
Implement methods `allocate(size_t n)` for allocating memory and `deallocate()`
for deallocating memory.

What skills this question evaluates: This question tests the candidate’s
understanding of lower-level memory management in C++, particularly the
concepts of memory allocation and deallocation without object construction and
destruction.

Solution:

cpp
#include <iostream>
using namespace std;
template <typename T>
class CustomAllocator {
private:
T* array;
public:
CustomAllocator() : array(nullptr) {}
T* allocate(size_t n) {
array = static_cast<T*>(operator new[](n * sizeof(T)));
return array;
}
void deallocate() {
operator delete[](array);
}
};
int main() {
CustomAllocator<int> allocator;
int* arr = allocator.allocate(5);
// Use the allocated array (construct objects if necessary)
for (int i = 0; i < 5; ++i) {
new (&arr[i]) int(i); // Placement new
}
// Manually call destructor for constructed objects
for (int i = 0; i < 5; ++i) {
arr[i].~int();
}
allocator.deallocate();
return 0;
}

Explanation of the solution: The `CustomAllocator` template class handles raw


memory allocation and deallocation for an array of type `T`. The `allocate`
method uses `operator new[]` to allocate unconstructed memory and returns a
pointer to this memory. The `deallocate` method frees the memory using
`operator delete[]`. In `main`, the allocated memory is used to manually
construct and destruct objects using placement new and explicit destructor calls,
demonstrating an understanding of memory allocation without automatic
construction and destruction. This example showcases a more advanced and
controlled approach to memory management in C++.

Concurrency and multithreading


Question 1: Implementing a thread-safe queue
Prompt: Create a C++ class `ThreadSafeQueue` that implements a thread-safe
queue using mutexes. The class should provide `enqueue` and `dequeue`
methods to add and remove items, ensuring thread safety.

What skills this question evaluates: This question tests the candidate’s
understanding of thread synchronization in C++ using mutexes. It evaluates the
ability to implement basic thread-safe data structures, crucial in multithreaded
applications.

Solution:

cpp
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
using namespace std;
template <typename T>
class ThreadSafeQueue {
private:
queue<T> queue;
mutex mtx;
condition_variable cv;
public:
void enqueue(T item) {
lock_guard<mutex> lock(mtx);
queue.push(item);
cv.notify_one();
}
T dequeue() {
unique_lock<mutex> lock(mtx);
cv.wait(lock, [this] { return !queue.empty(); });
T item = queue.front();
queue.pop();
return item;
}
};
int main() {
ThreadSafeQueue<int> tsQueue;
// Example usage: tsQueue.enqueue(10);
// Example usage: int item = tsQueue.dequeue();
return 0;
}

Explanation of the solution: The `ThreadSafeQueue` class uses a standard queue


and a mutex for synchronization. The `enqueue` method locks the mutex, adds an
item to the queue, and then notifies one waiting thread. The `dequeue` method
waits (without busy-waiting) until the queue is not empty and then removes an
item from the queue. This implementation ensures thread safety for enqueueing
and dequeueing operations, demonstrating key concepts in concurrent C++
programming.

Question 2: Implementing a simple thread pool


Prompt: Create a C++ class `ThreadPool` that manages a fixed number of threads.
The class should be able to execute tasks (function objects) added to a queue.
Implement methods to add tasks and to shut down the thread pool gracefully.
What skills this question evaluates: This question assesses advanced
understanding of multithreading, specifically the management of multiple threads
and task execution. It evaluates the ability to implement a thread pool and
manage its lifecycle.

Solution:

cpp
#include <iostream>
#include <vector>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <queue>
using namespace std;
class ThreadPool {
private:
vector<thread> workers;
queue<function<void()>> tasks;
mutex mtx;
condition_variable cv;
bool stop;
public:
ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(this->mtx);
this->cv.wait(lock, [this] { return
this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = this->tasks.front();
this->tasks.pop();
}
task();
}
});
}
}
void enqueue(function<void()> task) {
{
lock_guard<mutex> lock(mtx);
tasks.push(task);
}
cv.notify_one();
}
void shutdown() {
{
lock_guard<mutex> lock(mtx);
stop = true;
}
cv.notify_all();
for (thread &worker : workers) {
worker.join();
}
}
~ThreadPool() {
if (!stop) {
shutdown();
}
}
};
int main() {
ThreadPool pool(4);
// Example usage: pool.enqueue([]{ cout << "Task executed."
<< endl; });
return 0;
}

Explanation of the solution: The `ThreadPool` class manages a fixed number of


worker threads and a task queue. Worker threads execute tasks from the queue.
Tasks are function objects enqueued using the `enqueue` method. The
`shutdown` method stops all threads after completing any remaining tasks. The
use of mutexes and condition variables ensures thread-safe access to the task
queue and coordinated execution. This solution demonstrates a fundamental
pattern in concurrent programming: managing a pool of threads to efficiently
execute tasks.

Advanced features of C++


Question 1: Implementing a custom template metaprogram
Prompt: Write a C++ template metaprogram `Factorial` that computes the
factorial of a compile-time constant integer. Use template specialization to
achieve this.

What skills this question evaluates: : This question assesses advanced knowledge
of C++ template metaprogramming, an area that involves using templates to
perform computations at compile time. It evaluates the ability to use recursive
template instantiations and template specialization.

Solution:

cpp
#include <iostream>
template <unsigned int N>
struct Factorial {
static const unsigned int value = N * Factorial<N -
1>::value;
};
template <>
struct Factorial<0> {
static const unsigned int value = 1;
};
int main() {
std::cout << "Factorial of 5: " << Factorial<5>::value <<
std::endl;
return 0;
}
Explanation of the solution: The `Factorial` template struct calculates the
factorial of a number at compile time. It uses recursive template instantiation,
with each instance calculating part of the factorial. The specialized version of the
template for the base case `Factorial<0>` provides the stopping condition for the
recursion. This is a classic example of template metaprogramming, leveraging C++
templates’ powerful ability for compile-time computation.

Question 2: Utilizing advanced C++17 features


Prompt: Using C++17 features, write a function `processVariants` that takes a
`std::variant` of different types (e.g., `int`, `double`, `std::string`) and uses a
`std::visit` to apply a lambda function that prints the value regardless of its type.

What skills this question evaluates: This question tests understanding of newer
C++17 features, particularly `std::variant` and `std::visit`. It assesses the ability to
work with type-safe unions and visitation patterns, showcasing proficiency in
modern C++ idioms.

Solution:

cpp
#include <iostream>
#include <variant>
#include <string>
using VariantType = std::variant<int, double, std::string>;
void processVariants(const VariantType& var) {
std::visit([](const auto& value) {
std::cout << value << std::endl;
}, var);
}
int main() {
VariantType var1 = 10;
VariantType var2 = 3.14;
VariantType var3 = "Hello C++17";
processVariants(var1);
processVariants(var2);
processVariants(var3);
return 0;
}

Explanation of the solution: The function `processVariants` takes a `std::variant`


and uses `std::visit` along with a generic lambda to process and print the
contained value. The lambda uses auto type deduction to work with any type
contained in the variant. This example demonstrates how C++17 introduces more
flexible and type-safe ways to handle a set of types, streamlining what would
otherwise require more complex and less safe approaches.

Next steps & resources


Getting better at C++ interviewing requires patience and analytical thinking more
than just coding prowess. Understand each question deeply before starting to
code, and think through use cases thoroughly. Consider working out the logic on
paper before writing so you have a clear idea of what you’re trying to accomplish
with the code. Once the solution is complete, refine it to produce clean, well-
commented code, to facilitate ease in future writing. Thoroughly test the output,
dedicating time to explore potential edge cases to guarantee the completeness of
your solution.

By taking these steps with the practice questions above (and with more
specialized applications of C++ for game development, machine learning, and
others) you’ll set yourself up to cultivate a robust understanding of the
fundamentals through consistent practice, rather than trying to “cram” concepts
shortly before an interview. Practicing interview scenarios, either solo or with a
peer, can also help you build confidence and improve ability to problem-solve on
the spot.

CodeSignal Learn is a revolutionary learning product for anyone launching a


technical career, pivoting into a new role, building competitive and in-demand
skills for a job search, or leveling-up in their current role. Take courses in machine
learning, data science, Python programming, and more with one-on-one support
from the smartest AI guide in the universe, Cosmo. Sign up to get started for free.
    

Keep reading

ENGINEERING

How a tech consultant boosts her coding skills with CodeSignal


Learn
Whether you’re trying to break into tech, prepare for the job search, or level up
in your current

Read More
ENGINEERING

How to break into data science: Q&A guide


Introduction Do you enjoy making sense of numbers, using statistics, and
creating visualizations of data? If so, a

Read More

CODESIGNAL UPDATES

Product spotlight: CodeSignal Develop


We are living in exciting times, where technology is advancing faster than ever
before. Recent innovations in generative

Read More

Ready to optimize your tech recruiting process?

REQUEST A CALL

Prepare for your next CodeSignal evaluation

GET STARTED
Need product support?

CONTACT US

   

Products Solutions

Pre-Screen For Talent Acquisition

Interview For Engineering Leaders

Develop For IO Psychologists

Learn For Individuals

IDE

Evaluations

Pricing

Resources Company

Resource Library About CodeSignal

Blog Newsroom

Customer Stories Leadership

Interview Prep Talent Science

Knowledge Base

Integrations

API Docs
Copyright © 2023 CodeSignal, Inc. All rights reserved

Privacy Terms Master Subscription Agreement Security & Compliance Cookie Policy

Sitemap

You might also like