Skip to content

Commit 64f99f9

Browse files
author
Colin Robertson
committed
Fix 1809 and Acrolinx Welcome
1 parent 5f1cfad commit 64f99f9

1 file changed

Lines changed: 26 additions & 23 deletions

File tree

docs/cpp/welcome-back-to-cpp-modern-cpp.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
---
2-
title: "Welcome back to C++ (Modern C++)"
3-
ms.date: "11/19/2019"
2+
title: "Welcome back to C++ - Modern C++"
3+
description: "Describes the new programming idioms in Modern C++ and their rationale."
4+
ms.date: "01/10/2020"
45
ms.topic: "conceptual"
56
ms.assetid: 1cb1b849-ed9c-4721-a972-fd8f3dab42e2
67
---
7-
# Welcome back to C++ (Modern C++)
8+
# Welcome back to C++ - Modern C++
89

9-
Over the past 25 years, C++ has been one of the most widely used programming languages in the world. Well-written C++ programs are fast and efficient. The language is more flexible than other languages because it enables you to access low-level hardware features to maximize speed and minimize memory requirements. You can use it to create a wide range of apps—from games, to high-performance scientific software, device drivers, embedded programs, libraries and compilers for other programming languages, Windows client apps, and much more.
10+
Since its creation, C++ has become one of the most widely used programming languages in the world. Well-written C++ programs are fast and efficient. The language is more flexible than other languages: It can work at the highest levels of abstraction, and down at the level of the silicon. C++ supplies highly optimized standard libraries. It enables access to low-level hardware features, to maximize speed and minimize memory requirements. Using C++, you can create a wide range of apps. Games, device drivers, and high-performance scientific software. Embedded programs. Windows client apps. Even libraries and compilers for other programming languages get written in C++.
1011

11-
One of the original requirements for C++ was backward compatibility with the C language. As a result C++ has always permitted C-style programming with raw pointers, arrays, null-terminated character strings, custom data structures, and other features that may enable great performance but can also spawn bugs and complexity. The evolution of C++ has emphasized features that greatly reduce the need to use C-style idioms. The old C-programming facilities are there when you need them, but with modern C++ code you should need them less and less. Modern C++ code is simpler, safer, more elegant, and still as fast as ever.
12+
One of the original requirements for C++ was backward compatibility with the C language. As a result, C++ has always permitted C-style programming, with raw pointers, arrays, null-terminated character strings, and other features. They may enable great performance, but can also spawn bugs and complexity. The evolution of C++ has emphasized features that greatly reduce the need to use C-style idioms. The old C-programming facilities are there when you need them, but with modern C++ code you should need them less and less. Modern C++ code is simpler, safer, more elegant, and still as fast as ever.
1213

1314
The following sections provide an overview of the main features of modern C++. Unless noted otherwise, the features listed here are available in C++11 and later. In the Microsoft C++ compiler, you can set the [/std](../build/reference/std-specify-language-standard-version.md) compiler option to specify which version of the standard to use for your project.
1415

15-
## RAII and smart pointers
16+
## Resources and smart pointers
1617

17-
One of the major classes of bugs in C-style programming is the *memory leak* due to failure to call **delete** for memory that was allocated with **new**. Modern C++ emphasizes the principle of *resource acquisition is initialization* which states that any resource (heap memory, file handles, sockets, and so on) should be *owned* by an object that creates, or receives, the newly-allocated resource in its constructor, and deletes it in its destructor. By adhering to the principle of RAII, you guarantee that all resources will be properly returned to the operating system when the owning object goes out of scope. To support easy adoption of RAII principles, the C++ Standard Library provides three smart pointer types: [std::unique_ptr](../standard-library/unique-ptr-class.md), [std::shared_ptr](../standard-library/shared-ptr-class.md), and [std::weak_ptr](../standard-library/weak-ptr-class.md). A smart pointer handles the allocation and deletion of the memory it owns. The following example shows a class with an array member that is allocated on the heap in the call to `make_unique()`. The calls to **new** and **delete** are encapsulated by the `unique_ptr` class. When a `widget` object goes out of scope, the unique_ptr destructor will be invoked and it will release the memory that was allocated for the array.
18+
One of the major classes of bugs in C-style programming is the *memory leak*. Leaks are often caused by a failure to call **delete** for memory that was allocated with **new**. Modern C++ emphasizes the principle of *resource acquisition is initialization* (RAII). The idea is simple. Resources (heap memory, file handles, sockets, and so on) should be *owned* by an object. That object creates, or receives, the newly allocated resource in its constructor, and deletes it in its destructor. The principle of RAII guarantees that all resources get properly returned to the operating system when the owning object goes out of scope.
19+
20+
To support easy adoption of RAII principles, the C++ Standard Library provides three smart pointer types: [std::unique_ptr](../standard-library/unique-ptr-class.md), [std::shared_ptr](../standard-library/shared-ptr-class.md), and [std::weak_ptr](../standard-library/weak-ptr-class.md). A smart pointer handles the allocation and deletion of the memory it owns. The following example shows a class with an array member that is allocated on the heap in the call to `make_unique()`. The calls to **new** and **delete** are encapsulated by the `unique_ptr` class. When a `widget` object goes out of scope, the unique_ptr destructor will be invoked and it will release the memory that was allocated for the array.
1821

1922
```cpp
2023
#include <memory>
@@ -41,11 +44,11 @@ Whenever possible, use a smart pointer when allocating heap memory. If you must
4144

4245
## std::string and std::string_view
4346

44-
C-style strings are another major source of bugs. By using [std::string and std::wstring](../standard-library/basic-string-class.md) you can eliminate virtually all the errors associated with C-style strings, and gain the benefit of member functions for searching, appending, prepending, and so on. Both are highly optimized for speed. When passing a string to a function that requires only read-only access, in C++17 you can use [std::string_view](../standard-library/basic-string-view-class.md) for even greater performance benefit.
47+
C-style strings are another major source of bugs. By using [std::string and std::wstring](../standard-library/basic-string-class.md), you can eliminate virtually all the errors associated with C-style strings. You also gain the benefit of member functions for searching, appending, prepending, and so on. Both are highly optimized for speed. When passing a string to a function that requires only read-only access, in C++17 you can use [std::string_view](../standard-library/basic-string-view-class.md) for even greater performance benefit.
4548

4649
## std::vector and other Standard Library containers
4750

48-
The Standard Library containers all follow the principle of RAII, provide iterators for safe traversal of elements, are highly optimized for performance and have been thoroughly tested for correctness. By using these containers whenever possible, you eliminate the potential for bugs or inefficiencies that might be introduced in custom data structures. By default, use [vector](../standard-library/vector-class.md) as the preferred sequential container in C++. This is equivalent to `List<T>` in .NET languages.
51+
The Standard Library containers all follow the principle of RAII. They provide iterators for safe traversal of elements. And, they're highly optimized for performance and have been thoroughly tested for correctness. By using these containers, you eliminate the potential for bugs or inefficiencies that might be introduced in custom data structures. Instead of raw arrays, use [vector](../standard-library/vector-class.md) as a sequential container in C++.
4952

5053
```cpp
5154
vector<string> apples;
@@ -76,7 +79,7 @@ Before you assume that you need to write a custom algorithm for your program, fi
7679

7780
Here are some important examples:
7881

79-
- **for_each**, the default traversal algorithm (along with range-based for loops).
82+
- **for_each**, the default traversal algorithm (along with range-based for loops).
8083

8184
- **transform**, for not-in-place modification of container elements
8285

@@ -97,7 +100,7 @@ auto i = lower_bound( v.begin(), v.end(), comp );
97100
98101
## auto instead of explicit type names
99102
100-
C++11 introduced the [auto](auto-cpp.md) keyword for use in variable, function, and template declarations. **auto** tells the compiler to deduce the type of the object so that you do not have to type it explicitly. **auto** is especially useful when the deduced type is a nested template:
103+
C++11 introduced the [auto](auto-cpp.md) keyword for use in variable, function, and template declarations. **auto** tells the compiler to deduce the type of the object so that you don't have to type it explicitly. **auto** is especially useful when the deduced type is a nested template:
101104
102105
```cpp
103106
map<int,list<string>>::iterator i = m.begin(); // C-style
@@ -106,7 +109,7 @@ auto i = m.begin(); // modern C++
106109

107110
## Range-based for loops
108111

109-
C-style iteration over arrays and containers is prone to indexing errors and is also tedious to type. To eliminate these errors, and make your code more readable, use range-based for loops with Standard Library containers as well as raw arrays. For more information, see [Range-based for statement](../cpp/range-based-for-statement-cpp.md).
112+
C-style iteration over arrays and containers is prone to indexing errors and is also tedious to type. To eliminate these errors, and make your code more readable, use range-based for loops with both Standard Library containers and raw arrays. For more information, see [Range-based for statement](../cpp/range-based-for-statement-cpp.md).
110113

111114
```cpp
112115
#include <iostream>
@@ -132,7 +135,7 @@ int main()
132135

133136
## constexpr expressions instead of macros
134137

135-
Macros in C and C++ are tokens that are processed by the preprocessor prior to compilation. Each instance of a macro token is replaced with its defined value or expression before the file is compiled. Macros are commonly used in C-style programming to define compile-time constant values. However, macros are error-prone and difficult to debug. In modern C++, you should prefer [constexpr](constexpr-cpp.md) variables for compile-time constants:
138+
Macros in C and C++ are tokens that are processed by the preprocessor before compilation. Each instance of a macro token is replaced with its defined value or expression before the file is compiled. Macros are commonly used in C-style programming to define compile-time constant values. However, macros are error-prone and difficult to debug. In modern C++, you should prefer [constexpr](constexpr-cpp.md) variables for compile-time constants:
136139

137140
```cpp
138141
#define SIZE 10 / C-style
@@ -141,7 +144,7 @@ constexpr int size = 10; // modern C++
141144
142145
### Uniform initialization
143146
144-
In modern C++, you can use brace initialization for any type. This form of initialization is especially convenient when initializing arrays, vectors, or other containers. In the following example, `v2` is initialized with 3 instances of `S`. `v3` is initialized with 3 instances of `S` which are themselves initialized with braces. The compiler infers the type of each element based on the declared type of `v3`.
147+
In modern C++, you can use brace initialization for any type. This form of initialization is especially convenient when initializing arrays, vectors, or other containers. In the following example, `v2` is initialized with three instances of `S`. `v3` is initialized with three instances of `S` that are themselves initialized using braces. The compiler infers the type of each element based on the declared type of `v3`.
145148
146149
```cpp
147150
#include <vector>
@@ -178,11 +181,11 @@ For more information, see [Brace initialization](initializing-classes-and-struct
178181

179182
## Move semantics
180183

181-
Modern C++ provides *move semantics* which make it possible to eliminate unnecessary memory copies which in earlier versions of the language were unavoidable in certain situations. A *move* operation transfers ownership of a resource from one object to the next without making a copy. When implementing a class that owns a resource such as heap memory, file handles, and so on, you can define a *move constructor* and *move assignment operator* for it. The compiler will choose these special members during overload resolution in situations where a copy is not needed. The Standard Library container types invoke the move constructor on objects if one is defined. For more information, see [Move Constructors and Move Assignment Operators (C++)](move-constructors-and-move-assignment-operators-cpp.md).
184+
Modern C++ provides *move semantics*, which make it possible to eliminate unnecessary memory copies. In earlier versions of the language, copies were unavoidable in certain situations. A *move* operation transfers ownership of a resource from one object to the next without making a copy. When implementing a class that owns a resource (such as heap memory, file handles, and so on), you can define a *move constructor* and *move assignment operator* for it. The compiler will choose these special members during overload resolution in situations where a copy isn't needed. The Standard Library container types invoke the move constructor on objects if one is defined. For more information, see [Move Constructors and Move Assignment Operators (C++)](move-constructors-and-move-assignment-operators-cpp.md).
182185

183186
## Lambda expressions
184187

185-
In C-style programming, a function can be passed to another function by means of a *function pointer*. Function pointers are inconvenient to maintain and understand because the function they refer to may be defined elsewhere in the source code, far away from the point at which it is being invoked. Also, they are not type-safe. Modern C++ provides function objects, classes that override the [()](function-call-operator-parens.md) operator which enables them to be called like a function. The most convenient way to create function objects is with inline [lambda expressions](../cpp/lambda-expressions-in-cpp.md). The following example shows how to use a lambda expression to pass a function object, that the `for_each` function will invoke on each element in the vector:
188+
In C-style programming, a function can be passed to another function by using a *function pointer*. Function pointers are inconvenient to maintain and understand. The function they refer to may be defined elsewhere in the source code, far away from the point at which it's invoked. Also, they're not type-safe. Modern C++ provides *function objects*, classes that override the [()](function-call-operator-parens.md) operator, which enables them to be called like a function. The most convenient way to create function objects is with inline [lambda expressions](../cpp/lambda-expressions-in-cpp.md). The following example shows how to use a lambda expression to pass a function object, that the `for_each` function will invoke on each element in the vector:
186189

187190
```cpp
188191
std::vector<int> v {1,2,3,4,5};
@@ -191,23 +194,23 @@ In C-style programming, a function can be passed to another function by means of
191194
auto result = find_if(begin(v), end(v), [=](int i) { return i > x && i < y; });
192195
```
193196
194-
The lambda expression `[=](int i) { return i > x && i < y; }` can be read as "function that takes a single argument of type `int` and returns a boolean that indicates whether the expression is true. Notice that the variables `x` and `y` from the surrounding context can be used in the lambda. The `[=]` specifies that those variables are *captured* by value; in other words the lambda expression has its own copies of those values.
197+
The lambda expression `[=](int i) { return i > x && i < y; }` can be read as "function that takes a single argument of type `int` and returns a boolean that indicates whether the argument is greater than `x` and less than `y`." Notice that the variables `x` and `y` from the surrounding context can be used in the lambda. The `[=]` specifies that those variables are *captured* by value; in other words, the lambda expression has its own copies of those values.
195198
196199
## Exceptions
197200
198-
As a general rule, modern C++ emphasizes exceptions rather than error codes as the best way to report and handle error conditions. For more information, see [Modern C++ best practices for exceptions and error handling](errors-and-exception-handling-modern-cpp.md).
201+
Modern C++ emphasizes exceptions rather than error codes as the best way to report and handle error conditions. For more information, see [Modern C++ best practices for exceptions and error handling](errors-and-exception-handling-modern-cpp.md).
199202
200203
## std::atomic
201204
202205
Use the C++ Standard Library [std::atomic](../standard-library/atomic-structure.md) struct and related types for inter-thread communication mechanisms.
203206
204207
## std::variant (C++17)
205208
206-
Unions are commonly used in C-style programming to conserve memory by enabling members of different types to occupy the same memory location. However, unions are not type-safe and are prone to programming errors. C++17 introduces the [std::variant](../standard-library/variant-class.md) class as a more robust and safe alternative to unions. The [std::visit](../standard-library/variant-functions.md#visit) function can be used to access the members of a `variant` type in a type-safe manner.
209+
Unions are commonly used in C-style programming to conserve memory by enabling members of different types to occupy the same memory location. However, unions aren't type-safe and are prone to programming errors. C++17 introduces the [std::variant](../standard-library/variant-class.md) class as a more robust and safe alternative to unions. The [std::visit](../standard-library/variant-functions.md#visit) function can be used to access the members of a `variant` type in a type-safe manner.
207210
208211
## See also
209212
210-
[C++ Language Reference](../cpp/cpp-language-reference.md)<br/>
211-
[Lambda Expressions](../cpp/lambda-expressions-in-cpp.md)<br/>
212-
[C++ Standard Library](../standard-library/cpp-standard-library-reference.md)<br/>
213-
[Microsoft C++ language conformance table](../overview/visual-cpp-language-conformance.md)
213+
[C++ Language Reference](../cpp/cpp-language-reference.md)\
214+
[Lambda Expressions](../cpp/lambda-expressions-in-cpp.md)\
215+
[C++ Standard Library](../standard-library/cpp-standard-library-reference.md)\
216+
[Microsoft C++ language conformance table](../overview/visual-cpp-language-conformance.md)

0 commit comments

Comments
 (0)