Hire the top 3% of freelance C++ developers.

Toptal is a marketplace for top C++ developers, engineers, programmers, coders, architects, and consultants. Top companies and start-ups choose Toptal C++ freelancers for their mission-critical software projects.

We've been blown away by the level of talent we've been able to hire through Toptal.

Brad Rozran, Optimizely

Trusted by leading brands and startups

Our Exclusive Network of C++ Developers

Sam Varshavchik

C++ Developer

Sam is a senior freelance developer and architect with over 20 years of experience developing in the financial industry.

Hire Sam

Konstantin Kanishchev

C++ Developer

Konstantin is a Theoretical Physicist with a strong background in C++, Python, and JavaScript programming. With deep experience in research-level software d...evelopment, heavy data analysis (WLCG), and data visualization (d3.js), he provides high-level expertise in Physics, CS, and Applied Mathematics. 

Hire Konstantin

Richard Rozsa

C++ Developer

Richard Rozsa offers a vision of data as a self formatting entity. For more than 30 years, he's delivered top quality technical architecture, programming,... testing and solutions for complex problems--on-time and within budget. He's extremely flexible and able to integrate as a standalone freelancer or within teams. 

Hire Richard

Ken Whaley

C++ Developer

Ken is a top architect, engineer, and developer with over 30 years of experience in the field. He has a proven ability to understand, optimize, enhance, and... create from scratch significant software tools and workflows with large user bases that greatly magnify productivity for large groups of engineers. Ken is eager to take on new challenges and has done so with teams of all sizes and compositions.  

Hire Ken

Sasa Mrvos

C++ Developer

Sasa is a top architect/developer with a background in desktop, embedded systems, servers, and industrial solutions. He loves challenges, and if there is a... hard or seemingly impossible project, he just might like it. He enjoys working on signal processing, image processing, number crunching, compression, protocols, machine vision, compilers/parsers, and algorithms in general. 

Hire Sasa

Gustav Stieger

C++ Developer

Gustav is a software engineer with 25 years of experience with all levels of software and architecture. His skills include .NET/C#, ETL (extract-transform-l...oad), SQL (including database design), HTML, CSS, JavaScript, Windows Forms, and REST APIs. He is a creative, abstract, and theoretical thinker with the ability to turn ideas into reusable modules and solutions. He communicates extremely well and he has worked in teams of all sizes. 

Hire Gustav

Antonio Bello

C++ Developer

Antonio is an experienced, self-motivated, results-driven, flexible freelance professional who specializes in turning business ideas into software solutions.... He covers the entire software development life cycle, from concept to final product, using the best technologies. 

Hire Antonio

Dmitrii Polutov

C++ Developer

Dmitrii is a Software Engineer with a strong background in the development, design, and maintenance of new and existing software. He has extensive experienc...e programming across multiple platforms, writing C and C++ code for over two decades. 

Hire Dmitrii

Scott Ferrett

C++ Developer

Scott is a freelance architect and lead developer with extensive experience in C++, C#, and SQL. He has contributed to the ANSI standards for both C++ and... SQL. He excels with problems that are best solved with multiple cooperative processes.
 

Hire Scott

Viktor Kirilov

C++ Developer

Viktor has more than four years of experience developing for the games and VFX industries, but since 2015, he's been mainly working on open source projects... and contract work. He's passionate about game engines, high-performance code, data-oriented design, cryptocurrencies, minimizing friction, and incorporating good practices in the software development process such as testing and the use of tools. 

Hire Viktor

Ricardo Costa

C++ Developer

Ricardo has over ten years of experience as a professional developer focusing on game development, computer graphics (rendering, computer vision, and VR/AR)..., artificial intelligence, and client/server systems. He has also developed a variety of desktop and server applications in C#, C++, and Python. He is passionate about researching cutting-edge technology, creating real-time, high-performance software, and optimizing complex systems. 

Hire Ricardo

Hire C++ Developers Seamlessly with Toptal

1
Talk to One of Our Industry Experts
A Toptal director of engineering will work you to understand your goals, technical needs, and team dynamics.
2
Work With Hand-Selected Talent
Within days, we'll introduce you to the right C++ developer for your project. Average time to match is under 24 hours.
3
The Right Fit, Guaranteed
Work with your new C++ developer for a trial period (pay only if satisfied), ensuring they're the right fit before starting the engagement.

FAQs

  • How are Toptal C++ developers different?

    At Toptal, we thoroughly screen our C++ developers to ensure we only supply experts of the highest caliber. Of the more than 100,000 people who apply to join the Toptal network each year, we accept fewer than 3%. You'll work with engineering experts (never generalized recruiters or HR reps) to understand your goals, technical needs, and team dynamics. The end result: expertly-matched talent from our network, hand-selected to fit your business needs.

  • What is the no-risk trial period for C++ developers?

    We make sure that each engagement between you and your C++ developer begins with a trial period of up to two weeks. This means that you have time to confirm the engagement will be successful. If you're completely satisfied with the results, we'll bill you for the time and continue the engagement for as long as you'd like. If you're not completely satisfied, you won't be billed. From there, we can either part ways, or we can provide you with another expert who may be a better fit and with whom we will begin a second, no-risk trial.

  • How fast can I hire C++ developers through Toptal?

    Depending on availability and how fast you can progress, you could start your no-risk trial with a C++ developer within 48 hours of signing up. Most of our engagements start within 2 weeks of discussing your project with us.

Tap Into World-Class Talent

  • Trusted Experts Only

    All of our talent are seasoned experts who ramp up quickly, readily contribute as core team members, and work with you to minimize onboarding time.

  • The Right Fit

    We have a knack for matching you with the right fit. Start working with your new hire on a no-risk trial period, paying only if satisfied.

  • Scale as Needed

    Hire in under 2 weeks and scale your team up or down as needed, no strings attached.

  • Seamless Hiring

    We handle all aspects of billing, payments, and NDA’s. Let us take care of the overhead while you focus on building great products.

  • Flexible Engagements

    Choose the engagement type that suits your needs — hourly, part-time, or full-time — with the ability to change anytime.

  • Expert Talent Matching

    Focus on your project and enjoy support from your dedicated account executive and expert talent matcher.

Guide to Hiring a great C++ Developer

C++ is a powerful general purpose multi-paradigm programming language. The language's immense set of features, its overall complexity, lack of elegant external tooling that other popular languages have, and access to low-level resources makes this one of the most difficult programming languages to master. Taming this mammoth beast requires much experience and wisdom.

Read Hiring Guide

How to Hire a Great C++ Developer

C++ is a powerful general purpose multi-paradigm programming language. It powers some of the most performance intensive applications, and serves well to satisfy some particular niches, including but not limited to desktop applications, embedded applications, device drivers, game engines, and more. The language’s immense set of features, its overall complexity, lack of elegant external tooling that other popular languages have, and access to low-level resources makes this one of the most difficult programming languages to master. Taming this mammoth beast requires much experience and wisdom.

Harnessing the power of C++ requires nothing short of experience and wisdom

Harnessing the power of C++ requires nothing short of experience and wisdom

This hiring guide will help you identify C++ developers who not only know the basics, but also understand its relevant concepts in-depth and know their way around the various challenges and pitfalls of this powerful programming language.

Basics

Questions like the following are meant to figure out how familiar the candidate is with C++, and to see if they know all the quirks and nuances of the language.

Q: Consider the following snippet of code:

string ext = "";
switch(ext) {
case "cpp":
case "cc":
        cout << "C++ source file" << endl;
case "java":
        cout << "Java source file" << endl;
default;
        cout << "Unknown extension" << endl;
}

Explain what, if anything, is wrong with it? How can you improve this code or work around any issue in it?

The switch statement, in C++, only accepts types that are integral, enumerated or class which has a single conversion function to an integral or enumerated type. std::string in C++ is not a primitive type.

In C/C++, switch statements are typically implemented as branch tables. Generating them for integers, integer-like or enumerated types is easy, which is not the case for strings.

One way to work around this limitation, in this particular case, is by using a map:

map<string, string> m;
m["cpp"] = "C++ source file";
m["cc"] = m["cpp"];
m["java"] = "Java source file";

string ext = "cc";
string r = m[ext];
if(r != "") {
	cout << r << endl;
} else {
	cout << "Unknown extension" << endl;
}

In case ext is expected to hold unknown values, you might want to use m.find(ext) != m.end() to determine if the key actually exists first. This is because the [] operator will automatically increase the container’s size everytime a non-existence key is used.

Q: How do you implement a variadic function in C++?

Functions that can accept a variable number of arguments can be declared using an ellipsis as its last parameter:

int int_sum(int n, ...)

For example, the following function will accept an argument, n, followed by any number of additional arguments.

int int_sum(int n, ...) {
	va_list args;
	va_start(args, n);
	int r = 0;
	while(n--) {
		int x = va_arg(args, int);
		r += x;
	}
	va_end(args);
	return r;
}

However, starting C++11, Variadic templates can be used to achieve similar results, as they are type safe and do not perform automatic type conversions.

Q: What are the different ways of passing parameters in a function call? Explain how they are different.

  • Pass by value: this causes the parameter’s value to be copied. Typically used for primitive types where the overhead of copying the value is minimal. In newer standards, such as C++11, with move semantics even complex objects may be efficiently passed by value.

  • Pass by reference: this causes the parameter inside the function to alias the variable passed when the function is called. Parameters can also be passed by const reference. This is very similar to what pass by value does, except the underlying object is not copied.

Additionally, pass by pointer can be considered another way of passing parameters. Although not the most recommended way of passing parameters, this works by passing the memory location of a variable by value, allowing the function to access the original variable’s contents, as if by reference. Typically used when it is important to pass NULL as the parameter. However, recommended ways of dealing with optional parameters involve the use of external libraries.

Q: What is the expected output for the following snippet of code:

int a[2];
int *x = &a[0];
*x = 2;
*(++x) = 4;
cout << a[0] << endl;
cout << a[1] << endl;

Explain.

The expected output of this program is:

2
4

This is because:

  • We start by declaring an array of 2 ints.
  • We are then taking a pointer to the first element in x.
  • Next, we are updating the value pointed at by x to 2.
  • Finally, we are Incrementing the pointer to move to the 2nd element and updating the value pointed at by x now to 4.

Q: How are exceptions handled in C++?

In C++, exceptions are handled using try-catch blocks:

try {
	// Something that may throw an exception
} catch(int ex) {
}

Exceptions are thrown using a throw statement:

throw 42;

Here, 42 is the parameter which will be passed to the handler as the only argument. Within a catch block, this parameter can be omitted to rethrow the current exception.

In a try-catch block, multiple exception handlers can be specified using multiple catch blocks. The type specified for the catch block will determine if it will be used to handle a particular exception.

And, Beyond

Even though C++ is closer to the metal than most other popular programming languages, there is still a lot going on under the hood. A great C++ developers is very likely to have gained this knowledge, sometimes out of sheer curiosity and sometimes the hard way.

Q: In the following snippet of code:

int *arr1 = new int[10];
int arr2[10];
// ...
delete[] arr1;

Why is the delete[] statement necessary for variable arr1, but not for arr2? How can this be re-written using smart pointers?

Memory allocated dynamically using new or new[] must be deallocated to reclaim the used memory. This is because C++ doesn’t have a garbage collector to deallocate those resources automatically. The delete[] operator works on an array of objects that destroys each element before marking the memory as reusable on the heap.

The declaration line for arr1 could be replaced with the following:

unique_ptr<int[]> arr1(new int[10]);

This will automatically destroy and deallocate the array as soon as the smart pointer object goes out of scope.

Q: What is stack unwinding? What are its implications on object storage?

Stack unwinding happens when an exception is thrown. This is when function entries are removed from the stack up until an exception handler is found. In C++, stack unwinding will also cause stack variables to be destroyed automatically.

However, depending on how and when memory was allocated, stack winding may cause memory leaks. For example:

void leaky(bool panic) {
	SomeClass *scp = new SomeClass();
	if(panic) {
		throw 42;
	}
	delete scp;
}

Here, if panic is true, an exception will be thrown causing the program to never reach the delete statement and thus preventing the SomeClass instance to be deallocated from the heap.

Q: What is a function-try-block? What are these ideally used for?

A function-try-block allows you to attach a sequence of exception handlers after the function body that effectively treats the entire function body as a try block. This way, any exception that occurs with the function body may be handled by one of the catch blocks following it.

Ideally this syntax is used to log exceptions rather than handling them. Sometimes these are also used to modify the exception and rethrow them.

Q: What are templates? In terms of function declarations, how is this different from function overloading?

Templates are what allow C++ to define a group of classes, functions, types or variables in a parameterized manner. For example, the following definition of a function template:

template<typename T>
T add(T a, T b) {
	return a+b;
}

… will allow a developer to use the function add with any type that supports the + operator.

add(5, 1); // will use int add(int, int)
add(‘e’, ‘t’); // will use char add(char, char)

Templates allow classes, functions, etc. to be declared in a type “independent” way as long as the behavior remains the same. The compiler automatically generates the necessary code for every instance of the templated function or class used.

Templates are also not limited to types. They can also be used with expressions of a particular type. For example:

template<typename T, int a>
T add(T b) {
	return a+b;
}
add<int, 5>(1)

When it comes to functions, unlike function templates, function overloading requires you to explicitly define the behavior of each instance of the function.

Q: What are special member functions in C++? Briefly explain their use and state their defaults when not explicitly defined.

The default constructor, destructor, copy constructor and copy assignment (along with move constructor and assignment as introduced in C++11) are the special member functions in C++.

The default constructor is called when objects of a class are instantiated without passing any arguments. When no constructors are defined for a class, the default constructor is automatically defined as a function that is no-op.

The destructor, meant to serve as the opposite of constructors, allows an object to clean after itself before it is deallocated from memory. When not defined, similar to the default constructor, a no-op function is automatically declared on the class.

The copy constructor is essentially a constructor that accepts an argument of its own type by const reference. This constructor is meant to create a clone of the object being passed. When not defined, a default that copies all the members of the object is defined if and only if no move constructor or assignment function is defined.

The copy assignment function is called when an object is being assigned to another variable of the same type that is already initialized. Automatic default declaration follows the same rule as copy constructor as stated above.

Move constructor and assignment functions are similar to copy constructor and assignment functions, except that these are called when the values of the source object are no longer necessary and may be taken over by the destination object. The default behavior moves all members, but is automatically declared only when no copy constructor, assignment function, or move assignment function is declared.

Q: Does C++ allow multiple inheritance? What are some pitfalls of multiple inheritance and how can you work around them in C++?

C++ allows multiple inheritance. A class can extend one or more classes by providing a comma-separated list of their names:

class SomeClass: public ParentClass1, public ParentClass2 {
	// …
};

One of the pitfalls of multiple inheritance is ambiguity. For example, both ParentClass1 and ParentClass2 in the example above may have methods declared with the exact same signature. Attempting to call these inherited methods on SomeClass will cause the compiler to complain about this ambiguity - exactly which inherited method should be called? This issue can be worked around with explicit qualification:

SomeClass *sc = new SomeClass;
sc->ParentClass1::parentMethod();
sc->ParentClass2::parentMethod();

Another with multiple inheritance is the diamond problem. Let us assume that both ParentClass1 and ParentClass2 were derived from the same class:

class ParentClass1: public RootClass { /* … */ };
class ParentClass2: public RootClass { /* … */ };

… and if the RootClass had some public method named rootMethod, then calling that method would automatically result in ambiguity. This is because both ParentClass1 and ParentClass2 has inherited these methods, and to SomeClass this is ambiguous. One possible way of working around this issue is to use virtual inheritance:

class ParentClass1: public virtual RootClass { /* … */ };
class ParentClass2: public virtual RootClass { /* … */ };

Wrap up

The questions outlined in this guide cover some basic and some tricky aspects of C++. But just like its possibilities, the language’s hidden surprises are limitless, and that makes it difficult to cover everything about C++ in interviews. Therefore it is essential to evaluate a candidate’s competency and deep understanding of C++ through their ability to convey their ideas clearly and vividly.

We hope these questions will help you as a guide in your search for a true C++ expert. These rare elites may be hard to come by, but they will clearly stand out from the rest of the pack.

Top C++ Developers are in high demand.

Get Started