Once I was interviewed for the position of C ++ developer in one decent and even well-known office. I already had some experience then, I was even called a leading developer at my employer at that time. But when asked if I knew such things as DRY, KISS, YAGNI, NIH, I had to answer “No” over and over again.
I failed miserably, of course. But then the above abbreviations were googled and remembered. As I read thematic articles and books, prepared for interviews, and just talked with colleagues, I learned more new things, forgot them, googled again and understood. A couple of months ago, one of my colleagues casually mentioned in the IIFE working chat in the context of C ++. I, like that grandfather in a joke, almost fell off the stove and again got into Google.
It was then that I decided to compose (primarily for myself) a cheat sheet for abbreviations that are useful for a C ++ developer to know. This does not mean that they apply only to C ++, or that they are all-all-all concepts from C ++ (you can write volumes about language idioms). No, these are only concepts that I really encountered in work and interviews, usually expressed in the form of abbreviations. Well, I missed absolutely trivial things like LIFO, FIFO, CRUD, OOP, GCC and MSVC.
Nevertheless, the abbreviations came up decently, so I divided the cheat sheet into 2 parts: strongly characteristic of C ++ and more common. When it was appropriate, I grouped the concepts together, otherwise I simply listed them alphabetically. In general, there isn’t much sense in their order.
Basic things:
•
ODR
•
POD
•
POF
•
PIMPL
•
RAII
•
RTTI
•
STL
•
UB
Subtleties of the language:
•
ADL
•
CRTP
•
CTAD
•
EBO
•
IIFE
•
NVI
•
RVO and NRVO
•
SFINAE
•
SBO, SOO, SSO
UPDATE:
•
CV
•
LTO
•
PCH
•
PGO
•
SEH / VEH
•
TMP
•
VLA
Basic things
ODR
One Definition Rule. The rule of one definition. Simplified means the following:
- Within a single translation unit, each variable, function, class, etc., can have no more than one definition. There are as many advertisements (except for enumerations without a given base type, which simply cannot be declared without defining), but not more than one definition. Less possible if the entity is not used.
- Throughout the entire program, each non-inline function and variable used must have exactly one definition. Each inline function and variable used must have one definition in each translation unit.
- Some entities — for example, classes, inline functions and a variable, templates, enumerations, etc. — can have several definitions in a program (but not more than one in a translation unit). Actually, this happens when the same header containing a fully implemented class, for example, is connected to several .cpp files. But these definitions should coincide (I greatly simplify, but the essence is this). Otherwise it will be UB .
The compiler will easily catch an
ODR violation within a broadcast unit. But he won’t be able to do anything if the rule is violated at the program level — if only because the compiler processes one translation unit at a time.
The linker can find much more violations, but, strictly speaking, he is not obliged to do this (because, according to the Standard,
UB is here) and he can miss something. In addition, the process of searching for
ODR violations at the linking stage has quadratic complexity, and the assembly of C ++ code is not so fast.
As a result, the main responsibility for observing this rule (especially at the program level) is the developer himself. And yes - only entities with an external link can violate
ODR on a program scale; those from the inside (i.e. defined in anonymous namespaces) do not participate in this carnival.
Read more: one
time (English) ,
two (English)
Pod
Plain Old Data. Simple data structure. The simplest definition: this is such a structure that you can, as it is, in binary form send to / receive from the C library. Or, which is the same thing, correctly copy with simple
memcpy
.
From Standard to Standard, the full definition has changed in detail. The latest C ++ 17
POD currently defines how
- scalar type
- or a class / structure / union that:
- there is a trivial class
- there is a class with a standard device
- does not contain non- POD non-static fields
- or an array of these types
Trivial class
- has at least one not deleted:
- default constructor
- copy constructor
- moving constructor
- copy assignment operator
- move assignment operator
- all default constructors that copy and move constructors and assignment operators are trivial (simplified - generated by the compiler) or remote
- has a trivial non-remote destructor
- all base types and all fields of class types have trivial destructors
- no virtual methods (including destructor)
- no virtual base types
Class with a standard device (standard layout class):
However, in C ++ 20 there will no longer be a
POD type concept, only a trivial type and a type with a standard device will remain.
Read more:
one (Russian) ,
two (English) ,
three (English)
POF
Plain Old Function. A simple C-style function. Mentioned in the Standard prior to C ++ 14 inclusive only in the context of signal handlers. The requirements for it are:
- uses only things common to C and C ++ (i.e. no exceptions and
try-catch
, for example) - does not directly or indirectly cause non- POF functions, except atomic block-free operations (
std::atomic_init
, std::atomic_fetch_add
, etc.)
Only such functions, which also have a C link (
extern "C"
), are permitted by the Standard to be used as signal handlers. Support for other functions depends on the compiler.
In C ++ 17, the concept of
POF disappears; instead, a signal-safe evaluation appears
in the sense of signals . In such calculations are prohibited:
- calls to all functions of the standard library, except atomic, lock-free
-
new
and delete
calls - using
dynamic_cast
- call to
thread_local
entity - any work with exceptions
- initialization of a local static variable
- waiting for static variable initialization to complete
If the signal handler does any of the above, the Standard promises
UB .
Read more:
time (English)
PIMPL
Pointer To Implementation. Pointer to implementation. The classic idiom in C ++, also known as d-pointer, opaque pointer, compilation firewall. It consists in the fact that all private methods, fields, and other implementation details of a certain class are allocated into a separate class, and only public methods (i.e., an interface) and a pointer to an instance of this new separate class remain in the original class. For example:
foo.hpp class Foo { public: Foo(); ~Foo(); void doThis(); int doThat(); private: class Impl; std::unique_ptr<Impl> pImpl_; };
foo.cpp #include "foo.hpp" class Foo::Impl {
Why is this necessary, i.e. advantages:
- Encapsulation: users of the class through the header connection get only what they need - a public interface. If the implementation details change, the client code does not have to be recompiled (see ABI ).
- Compilation time: because the public header does not know anything about the implementation, it does not include the many headers it needs. Accordingly, the number of implicitly connected headers in the client code is reduced. The search for names and resolution of overloads is also simplified, because the public heading does not contain private members (although they are private, they participate in these processes).
Price, i.e., disadvantages:
Some of these shortcomings are removable, but the price is further complicating the code and introducing additional levels of abstraction (see
FTSE ).
Read more:
one (Russian) ,
two (Russian) ,
three (English)
RAII
Resource Acquisition Is Initialization. Capturing a resource is initialization. The meaning of this idiom is that the retention of a certain resource lasts throughout the life of the corresponding object. The capture of the resource occurs at the time of creation / initialization of the object, the release - at the time of destruction / finalization of the same object.
Oddly enough (primarily for C ++ programmers), this idiom is used in other languages, even those with a garbage collector. In Java, these are
try--
, in Python the
with
statement, in C # the
using
directive, in Go the
defer
. But it is in C ++ with its absolutely predictable life of objects that
RAII fits in especially organically.
In C ++, a resource is usually captured in the constructor and freed in the destructor. For example, smart pointers control memory this way, file streams manage files, mutex locks use mutexes. The beauty is that no matter how the block exits (scope) - is it normal through any of the exit points, or an exception was thrown - the resource control object created in this block will be destroyed, and the resource will be freed. Those. In addition to encapsulating
RAII in C ++, it also helps ensure security in the sense of exceptions.
Limitations, where without them. Destructors in C ++ do not return values and categorically should not throw exceptions. Accordingly, if the release of the resource is accompanied by one or another, you will have to implement additional logic in the destructor of the control object.
Read more:
one (Russian) ,
two (English)
RTTI
Run-Time Type Information. Type identification at runtime. This is a mechanism for obtaining information about the type of an object or expression at run time. It exists in other languages, but in C ++ it is used for:
-
dynamic_cast
-
typeid
and type_info
- exception catch
An important limitation:
RTTI uses a table of virtual functions, and therefore works only for polymorphic types (a virtual destructor is enough). An important explanation:
dynamic_cast
and
typeid
do not always use
RTTI , and therefore work for non-polymorphic types. For example, to dynamically cast a reference to a descendant to a link to an ancestor,
RTTI is not needed; all information is available at compile time.
RTTI is not free, albeit a little, but it negatively affects the performance and size of the memory consumed (hence the frequent advice not to use
dynamic_cast
due to its slowness). Therefore, compilers, as a rule, allow you to disable
RTTI . GCC and MSVC promise that this will not affect the correctness of catching exceptions.
Read more:
one (Russian) ,
two (English)
STL
Standard Template Library. Standard template library. Part of the C ++ standard library that provides generic containers, iterators, algorithms, and helper functions.
Despite its well-known name,
STL has never been so called in the Standard. Of the sections of the Standard, the
STL can clearly be attributed to the Containers library, Iterators library, Algorithm library, and partially the General utilities library.
In job descriptions, you can often find 2 separate requirements - knowledge of C ++ and familiarity with
STL . I never understood this, because
STL is an integral part of the language since the first 1998 Standard.
Read more:
one (Russian) ,
two (English)
UB
Undefined Behavior. Undefined behavior. This behavior is in those error cases for which the Standard has no requirements. Many of these are explicitly listed in the Standard as leading to
UB . These include, for example:
- violation of the boundaries of an array or STL container
- use of uninitialized variable
- null pointer dereference
- signed integer overflow
The result of
UB depends on everything in a row - both on the compiler version and on the weather on Mars. And this result can be anything: a compilation error, and correct execution, and crash. Indefinite behavior is evil, it is necessary to get rid of it.
Undefined behavior, on the other hand, should not be confused with
unspecified behavior . Unspecified behavior is the correct behavior of the correct program, but which, with the permission of the Standard, depends on the compiler. And the compiler is not required to document it. For example, this is the order in which the arguments of a function are evaluated or the implementation details of
std::map
.
Well, here you can recall the implementation-defined behavior. From unspecified differs in the availability of documentation. Example: the compiler is free to make the type
std::size_t
any size, but must indicate which one.
Read more:
one (Russian) ,
two (Russian) ,
three (English)
The subtleties of language
ADL
Argument-Dependent Lookup. Argument-dependent search. He is the search for Koenig - in honor of Andrew Koenig. This is a set of rules for resolving unqualified function names (i.e., names without the
::
operator), in addition to the usual name resolution. Simply put: the name of a function is looked up in the namespaces related to its arguments (this is the space containing the type of the argument, the type itself, if it is a class, all its ancestors, etc.).
Simplest example #include <iostream> namespace N { struct S {}; void f(S) { std::cout << "f(S)" << std::endl; }; } int main() { N::S s; f(s); }
The function
f
found in the namespace
N
only because its argument belongs to this space.
Even the trivial
std::cout << "Hello World!\n"
uses
ADL ,
std::basic_stream::operator<<
not overloaded for
const char*
. But the first argument to this statement is
std::basic_stream
, and the compiler searches and finds a suitable overload in the
std
.
Some details:
ADL is not applicable if a regular search found a declaration of a class member, or a function declaration in the current block without using
using
, or a declaration of neither a function nor a function template. Or if the function name is indicated in parentheses (the example above does not compile with
(f)(s)
; you will have to write
(N::f)(s);
).
Sometimes
ADL forces you to use fully qualified function names where it would seem unnecessary.
For example, this code does not compile namespace N1 { struct S {}; void foo(S) {}; } namespace N2 { void foo(N1::S) {}; void bar(N1::S s) { foo(s); } }
Read more:
one (English) ,
two (English) ,
three (English)
CRTP
Curiously Recurring Template Pattern. Strange recursive pattern. The essence of the template is as follows:
- some class inherits from the template class
- the descendant class is used as a template parameter of its base class
It’s easier to give an example:
template <class T> struct Base {}; struct Derived : Base<Derived> {};
CRTP is a prime example of static polymorphism. The base class provides an interface; the derived classes provide an implementation. But unlike ordinary polymorphism, there is no overhead for creating and using a table of virtual functions.
Example template <typename T> struct Base { void action() const { static_cast<T*>(this)->actionImpl(); } }; struct Derived : Base<Derived> { void actionImpl() const { ... } }; template <class Arg> void staticPolymorphicHandler(const Arg& arg) { arg.action(); }
When used correctly,
T
always a descendant of
Base
, so
static_cast
is enough to
static_cast
. Yes, in this case, the base class knows the descendant interface.
Another common area of use for
CRTP is to extend (or narrow down) the functionality of inherited classes (something called mixin in some languages). Perhaps the most famous examples:
-
struct Derived : singleton<Derived> { … }
-
struct Derived : private boost::noncopyable<Derived> { … }
-
struct Derived : std::enable_shared_from_this<Derived> { … }
-
struct Derived : counter<Derived> { … }
- count the number of created and / or existing objects
Disadvantages, or rather, moments requiring attention:
- There is no common base class; you cannot create a collection of different descendants and access them through a pointer to the base type. But if you want, you can inherit Base from the usual polymorphic type.
- There is an additional opportunity to shoot yourself inattentively:
Example template <typename T> struct Base {}; struct Derived1 : Base<Derived1> {}; struct Derived2 : Base<Derived1> {};
But you can add protection:
private: Base() = default; friend T;
- Because Since all methods are non-virtual, the descendant methods hide methods of the base class with the same names. Therefore, it is better to call them differently.
- In general, descendants have public methods that should not be used anywhere except the base class. This is not good, but is corrected through an additional level of abstraction (see FTSE ).
Read more:
one (Russian) ,
two (English)
CTAD
Class Template Argument Deduction. Automatically inferring the type of a class template parameter. This is a new feature from C ++ 17. Previously, only variable types (
auto
) and function template parameters were automatically displayed, which is why auxiliary functions like
std::make_pair
,
std::make_tuple
, etc.
std::make_tuple
. Now they are mostly not needed, because the compiler able to automatically display the parameters of class templates:
std::pair p{1, 2.0};
CTAD is a new opportunity, it still
needs to evolve and evolve (C ++ 20 already promises improvements). In the meantime, the restrictions are as follows:
Partial output of parameter types is not supported std::pair<double> p{1, 2};
Template aliases not supported template <class T, class U> using MyPair = std::pair<T, U>; MyPair p{1, 2};
Constructors available only in template specializations are not supported. template <class T> struct Wrapper {}; template <> struct Wrapper<int> { Wrapper(int) {}; }; Wrapper w{5};
Nested templates are not supported template <class T> struct Foo { template <class U> struct Bar { Bar(T, U) {}; }; }; Foo::Bar x{ 1, 2.0 };
Obviously, CTAD will not work if the type of the template parameter is not related to the constructor arguments. template <class T> struct Collection { Collection(std::size_t size) {}; }; Collection c{5};
In some cases, explicit inference rules that should be declared in the same block as the class template will help.
Example template <class T> struct Collection { template <class It> Collection(It from, It to) {}; }; Collection c{v.begin(), v.end()};
Read more:
one (Russian) ,
two (English)
EBO
Empty Base Optimization. Optimization of an empty base class. Also called Empty Base Class Optimization (EBCO).
As you know, in C ++, the size of an object of any class cannot be zero. Otherwise, all the arithmetic of pointers will break, because at one address it will be possible to mark as many different objects as you like. Therefore, even objects of empty classes (i.e., classes without a single non-static field) have some non-zero size, which depends on the compiler and OS and is usually equal to 1.
Thus, memory is wasted in vain on all objects of empty classes. But not the objects of their descendants, because in this case the Standard explicitly makes an exception. The compiler is allowed not to allocate memory for an empty base class and thus save not only 1 byte of the empty class, but all 4 (depending on the platform), since there is also alignment.
Example struct Empty {}; struct Foo : Empty { int i; }; std::cout << sizeof(Empty) << std::endl;
But
since different objects of the same type cannot be placed at the same address, the
EBO will not work if:
An empty class occurs twice among ancestors struct Empty {}; struct Empty2 : Empty {}; struct Foo : Empty, Empty2 { int i; }; std::cout << sizeof(Empty) << std::endl;
The first non-static field is an object of the same empty class or its descendant struct Empty {}; struct Foo : Empty { Empty e; int i; }; std::cout << sizeof(Empty) << std::endl;
In cases where objects of empty classes are non-static fields, no optimizations are provided (for now, the attribute
[[no_unique_address]]
will appear in C ++ 20). But spending 4 bytes (or how much the compiler needs) for each such field is a shame, so you can “collapse” objects of empty classes with the first non-empty non-static field on your own.
Example struct Empty1 {}; struct Empty2 {}; template <class Member, class ... Empty> struct EmptyOptimization : Empty ... { Member member; }; struct Foo { EmptyOptimization<int, Empty1, Empty2> data; };
Strange, but in this case, the Foo size is different for different compilers, for MSVC 2019 it is 8, for GCC 8.3.0 it is 4. But in any case, increasing the number of empty classes does not affect the
Foo
size.
Read more: one
time (English) ,
two (English)
IIFE
Immediately-Invoked Function Expression. Functional expression called immediately. In general, this is an idiom in JavaScript, from where Jason Turner borrowed it from the name. In fact, it's just creating and immediately calling a lambda:
const auto myVar = [&] { if (condition1()) { return computeSomeComplexStuff(); } return condition2() ? computeSonethingElse() : DEFAULT_VALUE; } ();
Why is this necessary? Well, for example, as in the above code in order to initialize a constant with the result of a non-trivial calculation and not clog the scope with unnecessary variables and functions.
Read more: one
time (English) ,
two (English)
NVI
Non-Virtual Interface. Non-virtual interface. According to this idiom, an open class interface should not contain virtual functions. All virtual functions are made private (maximum protected) and called inside open non-virtual.
Example class Base { public: virtual ~Base() = default; void foo() {
Why is this necessary:
- Each open virtual function does 2 things: defines the public interface of the class and participates in overriding behavior in descendant classes. The use of NVI eliminates such functions with a double load: the interface is defined by some functions, behavior change by others. You can change both of them independently of each other.
- If there are some general requirements for all options for implementing a virtual function (pre- and post-checks, mutex capture, etc.), then it is very convenient to collect them in one place (see DRY ) - in the base class - and prohibit the heirs from overriding this behavior. Those. it turns out a special case of the pattern Template method.
The fee for using NVI is some swelling of the code, possible performance degradation (due to one additional method call) and increased susceptibility to the problem of a fragile base class (see FBC ).
Read more: one time (English) , two (English)
RVO and NRVO
(Named) Return Value Optimization. Optimizing the (named) return value. This is a special case of copy elision permitted by the Standard - the compiler can omit unnecessary copies of temporary objects, even if their constructors and destructors have obvious side effects. Such optimization is permissible when the function returns an object by value (two other permitted cases of copy elision are the throwing and catching of exceptions).
Example Foo bar() { return Foo(); } int main() { auto f = bar(); }
Without RVO , a temporary object Foo
in the function would be created here bar
, then through the copy constructor another temporary object in the function would be created from it main
(to get the result bar
), and only then would the object be created f
and the value of the second temporary object would be assigned to it. RVO gets rid of all these copying and assignment, and the function bar
creates directly f
.
This happens approximately like this: a function main
allocates a space for an object in its stack frame f
. A function bar
(already working in its frame) gains access to this memory allocated in the previous frame and creates the desired object there.
NRVO is different fromRVO does the same optimization, but not when the object is created in the expression return
, but when the object previously created in the function is returned.
Example Foo bar() { Foo result; return result; }
Despite the seemingly small difference, NRVO is much more difficult to implement, and therefore it does not work in many cases. For example, if a function returns a global object or one of its arguments, or if a function has several exit points and different objects are returned through them, NRVO will not apply.
NRVO doesn't work here Foo bar(bool condition) { if (condition) { Foo f1; return f1; } Foo f2; return f2; }
Almost all compilers have long supported RVO . The degree of support for NRVO can vary from compiler to compiler and from version to version.
RVO and NRVO are just optimizations. And although copying the constructor and assignment operator are not called, they should be in the class of the object. The rules have changed a bit in C ++ 17: now RVO is not considered copy elision, it has become mandatory, and the corresponding constructor and assignment operator are not needed.
Note: (N) RVO in constant terms is a slippery topic. Until C ++ 14 inclusive, nothing was said about it, C ++ 17 requires RVO in such expressions, and the upcoming C ++ 20 - prohibits.
A few words about the connection with the semantics of displacement. Firstly, (N) RVO is still more effective, because no need to call the move constructor and destructor. Secondly, if instead result
of returning from the same function std::move(result)
, NRVO is guaranteed to not work. To paraphrase Standard: RVO applies to prvalue, NRVO applies to lvalue, a std::move(result)
is xvalue.
Read more: one (English) , two (English) , three (English)
SFINAE
Substitution Failure Is Not An Error. Failed substitution is not a mistake. SFINAE is a feature of the instantiation process of templates — functions and classes — in C ++. The bottom line is that if a certain template cannot be instantiated, this is not considered an error if there are other options. For example, a simplified algorithm for choosing the most appropriate function overload works like this:
- The name of the function is resolved - the compiler searches for all functions with the given name in all considered namespaces (see ADL ).
- Inappropriate functions are discarded - not the number of arguments, there is no necessary conversion of argument types, it was not possible to derive types for the function template, etc.
- (viable functions), . — .
So SFINAE occurs in the second step: if the overload is obtained by instantiating the function template, but the compiler could not infer the types of the signature of the function, then this overload is not considered an error, but is silently discarded (even without warning). And similarly for classes.
SFINAE can be used for many things, for example, for counting the length of an initialization list or for counting bits in a number. But most often, with its help, reflection is emulated at the very least, that is, it is determined if the class has a method with a certain signature.
Example #include <iostream> #include <type_traits> #include <utility> template <class, class = void> struct HasToString : std::false_type {}; // , // - , // — , , template <class T> struct HasToString<T, std::void_t<decltype(&T::toString)>> : std::is_same<std::string, decltype(std::declval<T>().toString())> {}; struct Foo { std::string toString() { return {}; } }; int main() { std::cout << HasToString<Foo>::value << std::endl; // 1 std::cout << HasToString<int>::value << std::endl; // 0 }
What appeared in C ++ 17 static if
may in some cases replace SFINAE , and the concepts expected in C ++ 20 will almost make it unnecessary. We'll see.
Read more: one (Russian) , two (English) , three (English)
SBO, SOO, SSO
Small Buffer / Object / String Optimization. Optimization of small buffers / objects / lines. Sometimes SSO is used in the meaning of Small Size Optimization, but it is very rare, so we assume that SSO is about strings. SBO and SOO are simply synonyms, and SSO is the most famous special case.
All data structures using dynamic memory certainly occupy some place on the stack as well. At least in order to store a pointer to a bunch. And the essence of these optimizations is not to request memory from the heap for relatively small objects (which is relatively expensive), but to place them in the already allocated stack space.
For example, std :: string could be implemented like this:
Example class string { char* begin_; size_t size_; size_t capacity_; };
The size of this class, I get 24 bytes (depending on the compiler and platform). Those.
strings no longer than 24 characters could be placed on the stack. Actually, not until 24, of course, since it is necessary to somehow distinguish between placement on the stack and on the heap. But here is the simplest way for short lines up to 8 characters (the same size - 24 bytes):
Example class string { union Buffer { char* begin_; char local_[8]; }; Buffer buffer_; size_t _size; size_t _capacity; };
In addition to the lack of allocations on the heap, there is another advantage - a high degree of data locality. An array or vector of such optimized objects will really only occupy a continuous piece of memory.
Almost all implementations std::string
use SSO and at least some implementations std::function
. But it is std::vector
never optimized in this way, because the Standard requires that std::swap
for two vectors it does not cause copying or assignment of their elements, and that all valid iterators remain valid. SBO will not allow to fulfill these requirements (for std::string
they are not). But boost::container::small_vector
, as you might guess, uses SBO .
Read more: time (English) ,two
UDPATE
Thanks to PyerK for this additional list of abbreviations.
CV
Qualifiers like const and volatile. const
means that the object / variable cannot be modified, an attempt to do this will result either in an error at compile time or in UB at run time. volatile
means that the object / variable can change regardless of the actions of the program (for example, some microcontroller fills writes something to memory), and the compiler should not optimize access to it. Access to an volatile
object not through a volatile
link or pointer also results in UB .
Read more: one (Russian) , two (English) , three (Russian)
LTO
Link Time Optimization. Link optimization. As the name implies, this optimization occurs during linking, i.e., after compilation. The linker can do what the compiler did not dare to: make some functions inline, throw out unused code and data. Increases link time, of course.
Read more: time (English)
PCH
Precompiled Headers. Precompiled headers. Often used, but rarely modified header files are compiled once and saved in the internal compiler format. Thus, reassembling a project will take less time, sometimes much less.
Read more: time (rus.)
Pgo
Profile-Guided Optimization. Optimization based on profiling results. This is a program optimization method, but not through static code analysis, but through test program launches and collecting real statistics. For example, branching and calling virtual functions in this way can be optimized.
Read more: time (rus.)
Seh / veh
Structured / Vectored Exception Handling. This is an MSVC extension for exception and error handling. Unlike standard try-catch
SEH uses its own keywords: __try
, __except
, __finally
, catches and handles are not explicitly thrown exceptions, and such things as access to an invalid memory stack overflow due to infinite recursion, call a pure virtual function, etc... VEH It does not catch every error explicitly, but creates a global chain of error handlers.
Read more: time (English)
Tmp
Template Meta-Programming. Template metaprogramming. Metaprogramming is when one program creates another as a result of its work. Templates in C ++ implement such metaprogramming. The template compiler generates the required number of classes or functions. It is known that TMP in C ++ is Turing-complete, i.e., any function can be implemented on it.
Read more: time (rus.)
VLA
Variable-Length Arrays. Arrays of variable length. Those.
arrays whose length is unknown at the compilation stage:
void foo(int n) { int array[n]; }
The C ++ standard does not allow this. Which is somewhat strange, because they exist in pure C since the C99 standard. And are supported by some C ++ compilers as an extension.
Read more: time (rus.)
PS
If I missed something or was mistaken somewhere - write in the comments. Just remember, please, that only abbreviations directly related to C ++ are listed here. For others, but no less useful, there will be a separate post.
The second part of