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++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

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

Интервал:

Закладка:

Сделать

Consider the effect that has when compilers have to determine which std::stringconstructor to call. There are two possibilities:

class string { // std::string is actually a

public: // typedef for std::basic_string

string(const string& rhs); // copy ctor

string(string&& rhs); // move ctor

};

In the Annotationconstructor's member initialization list, the result of std::move(text)is an rvalue of type const std::string. That rvalue can't be passed to std::string's move constructor, because the move constructor takes an rvalue reference to a non- const std::string. The rvalue can, however, be passed to the copy constructor, because an lvalue-reference-to- constis permitted to bind to a constrvalue. The member initialization therefore invokes the copy constructor in std::string, even though texthas been cast to an rvalue! Such behavior is essential to maintaining const-correctness. Moving a value out of an object generally modifies the object, so the language should not permit constobjects to be passed to functions (such as move constructors) that could modify them.

There are two lessons to be drawn from this example. First, don't declare objects constif you want to be able to move from them. Move requests on constobjects are silently transformed into copy operations. Second, std::movenot only doesn't actually move anything, it doesn't even guarantee that the object it's casting will be eligible to be moved. The only thing you know for sure about the result of applying std::moveto an object is that it's an rvalue.

The story for std::forwardis similar to that for std::move, but whereas std::move unconditionally casts its argument to an rvalue, std::forwarddoes it only under certain conditions. std::forwardis a conditional cast. To understand when it casts and when it doesn't, recall how std::forwardis typically used. The most common scenario is a function template taking a universal reference parameter that is to be passed to another function:

void process(const Widget& lvalArg); // process lvalues

void process(Widget&& rvalArg); // process rvalues

template // template that passes

void logAndProcess( T&& param) // param to process

{

auto now = // get current time

std::chrono::system_clock::now();

makeLogEntry("Calling 'process'", now);

process( std::forward(param));

}

Consider two calls to logAndProcess, one with an lvalue, the other with an rvalue:

Widget w;

logAndProcess(w); // call with lvalue

logAndProcess(std::move(w)); // call with rvalue

Inside logAndProcess, the parameter paramis passed to the function process. processis overloaded for lvalues and rvalues. When we call logAndProcesswith an lvalue, we naturally expect that lvalue to be forwarded to processas an lvalue, and when we call logAndProcesswith an rvalue, we expect the rvalue overload of processto be invoked.

But param, like all function parameters, is an lvalue. Every call to processinside logAndProcesswill thus want to invoke the lvalue overload for process. To prevent this, we need a mechanism for paramto be cast to an rvalue if and only if the argument with which paramwas initialized — the argument passed to logAndProcess— was an rvalue. This is precisely what std::forwarddoes. That's why std::forwardis a conditional cast: it casts to an rvalue only if its argument was initialized with an rvalue.

You may wonder how std::forwardcan know whether its argument was initialized with an rvalue. In the code above, for example, how can std::forwardtell whether paramwas initialized with an lvalue or an rvalue? The brief answer is that that information is encoded in logAndProcess's template parameter T. That parameter is passed to std::forward, which recovers the encoded information. For details on exactly how that works, consult Item 28.

Given that both std::moveand std::forwardboil down to casts, the only difference being that std::movealways casts, while std::forwardonly sometimes does, you might ask whether we can dispense with std::moveand just use std::forwardeverywhere. From a purely technical perspective, the answer is yes: std::forwardcan do it all. std::moveisn't necessary. Of course, neither function is really necessary , because we could write casts everywhere, but I hope we agree that that would be, well, yucky.

std::move's attractions are convenience, reduced likelihood of error, and greater clarity. Consider a class where we want to track how many times the move constructor is called. A static counter that's incremented during move construction is all we need. Assuming the only non-static data in the class is a std::string, here's the conventional way (i.e., using std::move) to implement the move constructor:

class Widget {

public:

Widget(Widget&& rhs)

: s( std::move(rhs.s))

{ ++moveCtorCalls; }

private:

static std::size_t moveCtorCalls;

std::string s;

};

To implement the same behavior with std::forward, the code would look like this:

class Widget {

public:

Widget(Widget&& rhs) // unconventional,

: s( std::forward(rhs.s)) // undesirable

{ ++moveCtorCalls; } // implementation

};

Note first that std::moverequires only a function argument ( rhs.s), while std::forwardrequires both a function argument ( rhs.s) and a template type argument ( std::string). Then note that the type we pass to std::forwardshould be a non-reference, because that's the convention for encoding that the argument being passed is an rvalue (see Item 28). Together, this means that std::moverequires less typing than std::forward, and it spares us the trouble of passing a type argument that encodes that the argument we're passing is an rvalue. It also eliminates the possibility of our passing an incorrect type (e.g., std::string&, which would result in the data member sbeing copy constructed instead of move constructed).

More importantly, the use of std::moveconveys an unconditional cast to an rvalue, while the use of std::forwardindicates a cast to an rvalue only for references to which rvalues have been bound. Those are two very different actions. The first one typically sets up a move, while the second one just passes — forwards — an object to another function in a way that retains its original lvalueness or rvalueness. Because these actions are so different, it's good that we have two different functions (and function names) to distinguish them.

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

Интервал:

Закладка:

Сделать

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

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


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

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

x