C++ Language
What is C++
C++ is a compiled language. For a program to run, its source text has to be processed by a compiler, producing object files, which are combined by a linker yielding an executable program. An executable program is created for a specific hardware/system combination, and is not portable.
The ISO C++ standard defines 2 kinds of entities:
- Core language features, such as built-in types and loops
- Standard-library components, such as containers (vector and map) and IO operations
C++ is statically typed: the type of each entity must be known to the compiler at its point of use.
References vs Pointers
A reference is similar to a pointer, except that you don’t need to use a prefix * to access the value referred to by the reference. In addition, a reference cannot be made to refer to a different object after its initialization.
int count_x(const char* p, char x) {
if (p == nullptr) return 0;
int count = 0;
for (; *p != 0; ++p) {
if (*p == x) {
++count;
}
}
return count;
}
C++ Guidelines
Follow the guidelines: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
Use General {}
style declarations
int i1 = 7.8; // i1 becomes 7
int i2 {7.8}; // error: floating-point to integer conversion
The old =
style is traditional and dates back to C. Conversions that
lose information, are allowed and implicitly applied. These are the
price paid for C compatibility.
Use non-member begin and end
non-member begin and end supports more containers, such as arrays.
vector<int> v;
int a[100];
// C++98
sort(v.begin(), v.end());
sort(&a[0], &a[0] + sizeof(a)/sizeof(a[0]));
// C++11
sort( begin(v), end(v) );
sort( begin(a), end(a) );
Lambda functions
variables get passed through the square brackets.
const int factor = 2;
std::for_each(myVec.begin(), myVec.end(), [factor](int& elem){
elem *= factor;
});
using
using is like typedef, but has less quirks.
using Month = int;
class Date {
// ...
public:
Month month() const; // do
int month(); // don't
// ...
};
avoid endl
The endl manipulator is mostly equivalent to ‘\n’ and “\n”; as most commonly used it simply slows down output by doing redundant flush()s. This slowdown can be significant compared to printf-style output.
Prefer using STL array or vector instead of a C array
C arrays are less safe, and have no advantages over array and vector. For a fixed-length array, use std::array, which does not degenerate to a pointer when passed to a function and does know its size. Also, like a built-in array, a stack-allocated std::array keeps its elements on the stack. For a variable-length array, use std::vector, which additionally can change its size and handles memory allocation.
On Namespacing
How do you properly use namespaces in C++? - Stack Overflow
RAII
Resource Acquisition Is Initialization or RAII, is a C++ programming technique which binds the life cycle of a resource that must be acquired before use (allocated heap memory, thread of execution, open socket, open file, locked mutex, disk space, database connection—anything that exists in limited supply) to the lifetime of an object.
The basic idea is that class destructors are always called when a particular instance of an object goes out of scope. This allows for automatic releasing of resources that will never be referenced.
For shared_ptr
, the class object contains a pointer to the object, and
a reference count for the number of pointers with access to the object
at the pointer. Once this reference count hits 0, the object is
released.
For unique_ptr
, there is no reference count within the class. once
this unique_ptr goes out of scope, the object at the pointer is
released. For this reason, unique_ptr
are more lightweight than
shared_ptr
, and cannot be copied. unique_ptr
can only be moved.
Array Decaying
It’s said that arrays “decay” into pointers. A C++ array declared as int numbers [5] cannot be re-pointed, i.e. you can’t say numbers = 0x5a5aff23. More importantly the term decay signifies loss of type and dimension; numbers decay into int* by losing the dimension information (count 5) and the type is not int [5] any more.
http://stackoverflow.com/questions/1461432/what-is-array-decaying
cin/cout vs scanf/printf
cin/cout is actually faster; but C++ slows it down to sync it with C-style io. If using only one style (cin), you can achieve greater IO speed with:
std::ios::sync_with_stdio(false);
Smart pointers
Here’s a summary of smart-pointers and their semantics. value_ptr is not in the stdlib, but is available as a C++ library.
shared_ptr
The main advantage of shared pointers is that, we should not worry
about calling delete or cleaning the memory in an explicit manner. The
shared pointer will take care of it once it goes out of scope. To
create a shared_ptr
, use make_shared
. It’s fast in memory allocation
compared to new
.
class Sample {
public:
Sample() { cout << "Constructor make_shared" << endl; }
~Sample() { cout << "Destructor make_shared" << endl; }
};
int main() {
shared_ptr<Sample> sp = make_shared<Sample>();
return 0;
}
unique_ptr
Like shared_ptr<>, there is no need to call delete or clean the memory
in an explicit manner. The unique pointer will take care of it once it
goes out of scope. shared_ptr<>
maintains reference counts where more
than one shared_ptr<> can refer to a single object.
This is prevented by unique_ptr<>
and the reason behind naming it as
unique. In unique_ptr<>
, one and only one unique_ptr<>
has the
ownership of the Object and manages its lifetime.
std::move
In unique_ptr, std::move is used to transfer the ownership from one unique_ptr to another, which is otherwise not possible.
For shared_ptr, std::move prevents the increment and immediate decrement of the reference count, making it an optimization. It’s not strictly necessary.
not_null
not_null is available in GSL, and with compile-time guarantees that a pointer is not null.
Books to read
http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list
Links
<biblio.bib>