C++ Coding Best Practices
In this lesson: Write clean, safe C++ — RAII, const, references, smart pointers, naming — bad vs good examples. In Hindi & English.
What are coding best practices?
A C++ program can compile, run and even give the right output — and still be hard to read, easy to break and full of hidden bugs. Best practices are the habits experienced programmers follow so that code stays correct, readable and easy to change. They are not extra syntax to learn; they are choices you make every time you write a line.
This lesson collects the practices that matter most for students and beginners, each with a short "avoid" and "prefer" example.
1. Names that explain themselves
A good name removes the need for a comment. Use nouns for variables, verbs for functions, and avoid single letters except loop counters.
// Avoid
int a, b, c;
int f(int x, int y) { return x * y / 100; }
// Prefer
int totalMarks, maxMarks, percentage;
int calculatePercentage(int obtained, int maximum) {
return obtained * 100 / maximum;
}Pick one style and stick to it: camelCase for variables and functions and PascalCase for classes is common. Constants are often written as MAX_STUDENTS or kMaxStudents.
2. Consistent indentation and braces
Indent each block by the same amount (4 spaces is typical) and always use braces, even for a single statement. Missing braces is a classic source of bugs:
// Avoid — only the first line is inside the if
if (marks >= 33)
cout << "Pass\n";
passCount++; // runs for everyone!
// Prefer
if (marks >= 33) {
cout << "Pass\n";
passCount++;
}Most editors (VS Code, Code::Blocks, Dev-C++) can auto-format your file — use it.
3. Initialise every variable
A local variable that is declared but not given a value contains garbage. Reading it is undefined behaviour.
int sum; // Avoid: garbage value
int sum = 0; // Prefer
int count{}; // Prefer: brace-initialised to 04. Use const wherever a value must not change
const documents intent and lets the compiler stop accidental changes. Use it for fixed values, for function parameters you only read, and for member functions that do not modify the object.
const double PI = 3.14159;
double area(const double radius) { // radius is read-only here
return PI * radius * radius;
}
void printReport(const std::string& name) { // no copy, no change
std::cout << name << '\n';
}5. Keep functions small and focused
A function should do one job. If main() is 200 lines long, split it: readMarks(), calculateResult(), printReport(). Small functions are easier to test, reuse and debug. A useful rule: if you need a comment to explain a block inside a function, that block probably wants to be its own function.
6. No magic numbers
// Avoid
if (attendance < 75) { ... }
// Prefer
const int MIN_ATTENDANCE_PERCENT = 75;
if (attendance < MIN_ATTENDANCE_PERCENT) { ... }Now the rule has a name, and changing it later means changing one line.
7. Prefer std::string and std::vector over raw arrays
Raw C arrays do not know their size and do not check bounds. std::vector grows as needed, knows its size(), and at() checks the index.
#include <vector>
std::vector<int> marks = {78, 91, 66};
marks.push_back(84);
for (int m : marks) std::cout << m << ' ';Likewise, use std::string instead of char name[20] — no buffer overflows and easy comparison with ==.
8. Let objects manage memory (RAII)
Avoid bare new/delete. If you need a heap object, use a smart pointer; it frees memory automatically when it goes out of scope.
#include <memory>
// Avoid
Student* s = new Student("Aman");
// ... an early return here leaks memory
delete s;
// Prefer
auto s = std::make_unique<Student>("Aman"); // freed automaticallySee smart pointers and dynamic memory for details.
9. Pass large objects by const reference
Passing a std::string or std::vector by value copies it. Pass by const& when you only read it, and by & when the function must change it.
double average(const std::vector<int>& marks); // read only, no copy void addBonus(std::vector<int>& marks, int bonus); // modifies caller's data
10. Turn on warnings and fix them
g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o main
Warnings such as "unused variable", "comparison of signed and unsigned" or "may be used uninitialised" usually point at real bugs. While testing, add -g -fsanitize=address,undefined to catch out-of-range access at run time.
11–15. Other habits worth building
- Comment the why, not the what.
i++; // increment iadds nothing;// skip header rowexplains intent. - Declare variables close to first use, in the smallest scope possible.
- Check input.
if (!(cin >> age)) { ... }handles a user typing letters instead of a number. - **Avoid
using namespace std;in header files.** It is acceptable in a small.cpppractice file. - Don't repeat yourself. If you copy-paste a block three times, turn it into a function or a loop.
Example: messy code vs clean code
Both programs below compute a student's percentage. The first works, but the second is what a reviewer — or an examiner — wants to see.
#include<iostream>
using namespace std;
int main(){int a,b;cin>>a>>b;
cout<<a*100/b;}#include <iostream>
int calculatePercentage(int obtained, int maximum) {
if (maximum <= 0) {
return 0; // avoid division by zero
}
return obtained * 100 / maximum;
}
int main() {
int obtainedMarks = 0;
int maximumMarks = 0;
std::cout << "Obtained marks: ";
std::cin >> obtainedMarks;
std::cout << "Maximum marks: ";
std::cin >> maximumMarks;
std::cout << "Percentage: "
<< calculatePercentage(obtainedMarks, maximumMarks) << "%\n";
return 0;
}The clean version names everything, guards against a zero divisor, separates calculation from input/output, and is laid out so each step is obvious.
Common mistakes
- Writing the whole program inside
main(). - Ignoring compiler warnings because "it still runs".
- Mixing
new/deletewith manual error handling — and leaking memory on the error path. - Comparing
intwithvector.size()(unsigned) in loops and getting warnings; usestd::size_tor a range-basedfor. - Leaving debug
coutlines in submitted code.
Take any program you wrote last month. Rename every variable to a meaningful name, split main() into at least three functions, add const where possible and compile with -Wall -Wextra until there are zero warnings.
Summary
- Clear names and consistent formatting make code readable.
- Initialise variables, use
const, and avoid magic numbers. - Keep functions small; pass big objects by
const&. - Prefer
std::vector,std::stringand smart pointers over raw arrays andnew/delete. - Compile with warnings on and treat them as bugs.
Related: structure of a C++ program, comments in C++, C++ interview questions.
Frequently Asked Questions
What are the most important C++ coding best practices for beginners?
const, initialise every variable, prefer std::vector/std::string over raw arrays and pointers, and compile with warnings turned on (-Wall -Wextra). These few habits prevent most beginner bugs.Should I use using namespace std in C++?
.cpp file. Never put it in a header file, because every file that includes the header inherits it and name clashes become likely. In larger projects write std:: or use narrow declarations like using std::cout;.Why should I avoid raw new and delete in modern C++?
new needs exactly one matching delete, and an early return or an exception easily skips it, leaking memory. Containers like std::vector and smart pointers like std::unique_ptr release memory automatically when they go out of scope (RAII), so the leak cannot happen.What compiler flags help catch mistakes in C++?
-Wall -Wextra -pedantic to see common warnings, and -g with -fsanitize=address,undefined while testing to catch out-of-bounds access and undefined behaviour at run time. Treat warnings as errors to fix, not noise.