Style guidelines are not overly strict. The important thing is that code is clear and readable with an appropriate amount of whitespace and reasonable length lines.
Tabs are not allowed, and a mixture of tabs and spaces is strictly forbidden. Modern autoindenting IDEs and editors require a consistent standard to be set.
int myFunction(bool t_b)
{
if (t_b)
{
// do something
}
}
Leaving them off can lead to semantic errors in the code.
// this compiles and does what you want, but can lead to confusing
// errors if close attention is not paid.
for (int i = 0; i < 15; ++i)
std::cout << i << std::endl;
// the cout is not part of the loop in this case even though it appears to be
int sum = 0;
for (int i = 0; i < 15; ++i)
++sum;
std::cout << i << std::endl;
// Correct
int sum = 0;
for (int i = 0; i < 15; ++i) {
++sum;
std::cout << i << std::endl;
}
// bad and hard to follow
if (x && y && myFunctionThatReturnsBool() && caseNumber3 && (15 > 12 || 2 < 3)) {
}
// better
if (x && y && myFunctionThatReturnsBool()
&& caseNumber3
&& (15 > 12 || 2 < 3)) {
}
Raw memory access, allocation and deallocation are difficult to get correct in C++ without risking memory errors and leaks. C++11 provides tools to avoid these problems.
// bad
MyClass *myobj = new MyClass;
// ...
delete myobj;
// Good
std::shared_ptr<MyClass> myobj = make_shared<MyClass>();
// ...
// myobj is automatically freed for you whenever it is no longer used.
this includes singleton objects
with the member initializer list
// bad
class MyClass
{
public:
MyClass(int t_value)
{
m_value = t_value;
}
private:
int m_value;
};
// good
class MyClass
{
public:
MyClass(int t_value)
: m_value(t_value)
{
}
private:
int m_value;
};
... when it is semantically correct. Pre-increment is faster then post-increment because it does not require a copy of the object to be made.
// Correct
for (int i = 0; i < 15; ++i)
{
std::cout << i << std::endl;
}
// incorrect
for (int i = 0; i < 15; i++)
{
std::cout << i << std::endl;
}
const
tells the compiler that a variable or method is immutable. This helps the compiler optimize the code and helps the developer know if a function side effects. Also, using const &
prevents the compiler from copying data unnecessarily.
// bad
class MyClass
{
public:
MyClass(std::string t_value)
: m_value(t_value)
{
}
std::string get_value()
{
return m_value;
}
private:
std::string m_value;
}
// good
class MyClass
{
public:
MyClass(const std::string &t_value)
: m_value(t_value)
{
}
std::string get_value() const
{
return m_value;
}
private:
std::string m_value;
}
Very nice and detailed, thank you.