Scott Meyers - Effective Modern C++

Здесь есть возможность читать онлайн «Scott Meyers - Effective Modern C++» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Sebastopol, Год выпуска: 2014, ISBN: 2014, Издательство: O’Reilly, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Effective Modern C++: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Effective Modern C++»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Coming to grips with C++11 and C++14 is more than a matter of familiarizing yourself with the features they introduce (e.g., auto type declarations, move semantics, lambda expressions, and concurrency support). The challenge is learning to use those features
— so that your software is correct, efficient, maintainable, and portable. That's where this practical book comes in. It describes how to write truly great software using C++11 and C++14 — i.e., using
C++.
Topics include:
■ The pros and cons of braced initialization,
specifications, perfect forwarding, and smart pointer make functions
■ The relationships among
,
, rvalue references, and universal references
■ Techniques for writing clear, correct,
lambda expressions
■ How
differs from
, how each should be used, and how they relate to C++'s concurrency API
■ How best practices in “old” C++ programming (i.e., C++98) require revision for software development in modern C++
Effective Modern C++ For more than 20 years,
'
books (
,
, and
) have set the bar for C++ programming guidance. His clear, engaging explanations of complex technical material have earned him a worldwide following, keeping him in demand as a trainer, consultant, and conference presenter. He has a Ph.D. in Computer Science from Brown University.
“After I learned the C++ basics, I then learned how to use C++ in production code from Meyers' series of Effective C++ books. Effective Modern C++ is the most important how-to book for advice on key guidelines, styles, and idioms to use modern C++ effectively and well. Don't own it yet? Buy this one. Now.”
Herb Sutter
Chair of ISO C++ Standards Committee and C++ Software Architect at Microsoft

Effective Modern C++ — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Effective Modern C++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

An alternative approach is to make addNamea function template taking a universal reference (see Item 24):

class Widget {

public:

template // take lvalues

void addName( T&& newName) // and rvalues;

{ // copy lvalues,

names.push_back(std::forward(newName)); // move rvalues;

} // see Item 25

// for use of

… // std::forward

};

This reduces the source code you have to deal with, but the use of universal references leads to other complications. As a template, addName's implementation must typically be in a header file. It may yield several functions in object code, because it not only instantiates differently for lvalues and rvalues, it also instantiates differently for std::stringand types that are convertible to std::string(see Item 25). At the same time, there are argument types that can't be passed by universal reference (see Item 30), and if clients pass improper argument types, compiler error messages can be intimidating (see Item 27).

Wouldn't it be nice if there were a way to write functions like addNamesuch that lvalues were copied, rvalues were moved, there was only one function to deal with (in both source and object code), and the idiosyncrasies of universal references were avoided? As it happens, there is. All you have to do is abandon one of the first rules you probably learned as a C++ programmer. That rule was to avoid passing objects of user-defined types by value. For parameters like newNamein functions like addName, pass by value may be an entirely reasonable strategy.

Before we discuss why pass-by-value may be a good fit for newNameand addName, let's see how it would be implemented:

class Widget {

public:

void addName( std::stringnewName) // take lvalue or

{ names.push_back(std::move(newName)); } // rvalue; move it

};

The only non-obvious part of this code is the application of std::moveto the parameter newName. Typically, std::moveis used with rvalue references, but in this case, we know that (1) newNameis a completely independent object from whatever the caller passed in, so changing newNamewon't affect callers and (2) this is the final use of newName, so moving from it won't have any impact on the rest of the function.

The fact that there's only one addNamefunction explains how we avoid code duplication, both in the source code and the object code. We're not using a universal reference, so this approach doesn't lead to bloated header files, odd failure cases, or confounding error messages. But what about the efficiency of this design? We're passing by value . Isn't that expensive?

In C++98, it was a reasonable bet that it was. No matter what callers passed in, the parameter newNamewould be created by copy construction . In C++11, however, addNamewill be copy constructed only for lvalues. For rvalues, it will be move constructed . Here, look:

Widget w;

std::string name("Bart");

w.addName(name); // call addName with lvalue

w.addName(name + "Jenne"); // call addName with rvalue

// (see below)

In the first call to addName(when nameis passed), the parameter newNameis initialized with an lvalue. newNameis thus copy constructed, just like it would be in C++98. In the second call, newNameis initialized with the std::stringobject resulting from a call to operator+for std::string(i.e., the append operation). That object is an rvalue, and newNameis therefore move constructed.

Lvalues are thus copied, and rvalues are moved, just like we want. Neat, huh?

It is neat, but there are some caveats you need to keep in mind. Doing that will be easier if we recap the three versions of addNamewe've considered:

class Widget { // Approach 1:

public: // overload for

void addName( const std::string&newName) // lvalues and

{ names.push_back(newName); } // rvalues

void addName( std::string&&newName)

{ names.push_back(std::move(newName)); }

private:

std::vector names;

};

class Widget { // Approach 2:

public: // use universal

template// reference

void addName( T&& newName)

{ names.push_back(std::forward(newName)); }

};

class Widget { // Approach 3:

public: // pass by value

void addName( std::stringnewName)

{ names.push_back(std::move(newName)); }

};

I refer to the first two versions as the “by-reference approaches,” because they're both based on passing their parameters by reference.

Here are the two calling scenarios we've examined:

Widget w;

std::string name("Bart");

w.addName(name); // pass lvalue

w.addName(name + "Jenne"); // pass rvalue

Now consider the cost, in terms of copy and move operations, of adding a name to a Widgetfor the two calling scenarios and each of the three addNameimplementations we've discussed. The accounting will largely ignore the possibility of compilers optimizing copy and move operations away, because such optimizations are context- and compiler-dependent and, in practice, don't change the essence of the analysis.

Overloading: Regardless of whether an lvalue or an rvalue is passed, the caller's argument is bound to a reference called newName. That costs nothing, in terms of copy and move operations. In the lvalue overload, newNameis copied into Widget::names. In the rvalue overload, it's moved. Cost summary: one copy for lvalues, one move for rvalues.

Using a universal reference: As with overloading, the caller's argument is bound to the reference newName. This is a no-cost operation. Due to the use of std::forward, lvalue std::stringarguments are copied into Widget::names, while rvalue std::stringarguments are moved. The cost summary for std::stringarguments is the same as with overloading: one copy for lvalues, one move for rvalues.

Item 25explains that if a caller passes an argument of a type other than std::string, it will be forwarded to a std::stringconstructor, and that could cause as few as zero std::stringcopy or move operations to be performed. Functions taking universal references can thus be uniquely efficient. However, that doesn't affect the analysis in this Item, so we'll keep things simple by assuming that callers always pass std::stringarguments.

Passing by value: Regardless of whether an lvalue or an rvalue is passed, the parameter newNamemust be constructed. If an lvalue is passed, this costs a copy construction. If an rvalue is passed, it costs a move construction. In the body of the function, newNameis unconditionally moved into Widget::names. The cost summary is thus one copy plus one move for lvalues, and two moves for rvalues. Compared to the by-reference approaches, that's one extra move for both lvalues and rvalues.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Effective Modern C++»

Представляем Вашему вниманию похожие книги на «Effective Modern C++» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Effective Modern C++»

Обсуждение, отзывы о книге «Effective Modern C++» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x