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

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

Интервал:

Закладка:

Сделать

class Widget { // in "widget.h"

public:

Widget();

private:

struct Impl;

std::unique_ptr<Impl >pImpl; // use smart pointer

}; // instead of raw pointer

and this for the implementation file:

#include "widget.h" // in "widget.cpp"

#include "gadget.h"

#include

#include

struct Widget::Impl { // as before

std::string name; std::vector data;

Gadget g1, g2, g3;

};

Widget::Widget() // per Item 21, create

: pImpl( std::make_unique<Impl >()) // std::unique_ptr

{} // via std::make_unique

You'll note that the Widgetdestructor is no longer present. That's because we have no code to put into it. std::unique_ptrautomatically deletes what it points to when it (the std::unique_ptr) is destroyed, so we need not delete anything ourselves. That's one of the attractions of smart pointers: they eliminate the need for us to sully our hands with manual resource release.

This code compiles, but, alas, the most trivial client use doesn't:

#include "widget.h"

Widget w; // error!

The error message you receive depends on the compiler you're using, but the text generally mentions something about applying sizeofor deleteto an incomplete type. Those operations aren't among the things you can do with such types.

This apparent failure of the Pimpl Idiom using std::unique_ptrs is alarming, because (1) std::unique_ptris advertised as supporting incomplete types, and (2) the Pimpl Idiom is one of std::unique_ptrs most common use cases. Fortunately, getting the code to work is easy. All that's required is a basic understanding of the cause of the problem.

The issue arises due to the code that's generated when wis destroyed (e.g., goes out of scope). At that point, its destructor is called. In the class definition using std::unique_ptr, we didn't declare a destructor, because we didn't have any code to put into it. In accord with the usual rules for compiler-generated special member functions (see Item 17), the compiler generates a destructor for us. Within that destructor, the compiler inserts code to call the destructor for Widget's data member pImpl. pImplis a std::unique_ptr, i.e., a std::unique_ptrusing the default deleter. The default deleter is a function that uses delete on the raw pointer inside the std::unique_ptr. Prior to using delete, however, implementations typically have the default deleter employ C++11's static_assertto ensure that the raw pointer doesn't point to an incomplete type. When the compiler generates code for the destruction of the Widget w, then, it generally encounters a static_assertthat fails, and that's usually what leads to the error message. This message is associated with the point where wis destroyed, because Widget's destructor, like all compiler-generated special member functions, is implicitly inline. The message itself often refers to the line where wis created, because it's the source code explicitly creating the object that leads to its later implicit destruction.

To fix the problem, you just need to make sure that at the point where the code to destroy the std::unique_ptris generated, Widget::Implis a complete type. The type becomes complete when its definition has been seen, and Widget::Implis defined inside widget.cpp. The key to successful compilation, then, is to have the compiler see the body of Widget's destructor (i.e., the place where the compiler will generate code to destroy the std::unique_ptrdata member) only inside widget.cppafter Widget::Implhas been defined.

Arranging for that is simple. Declare Widget's destructor in widget.h, but don't define it there:

class Widget { // as before, in "widget.h"

public:

Widget();

~Widget(); // declaration only

private: // as before

struct Impl;

std::unique_ptr pImpl;

};

Define it in widget.cppafter Widget::Implhas been defined:

#include "widget.h" // as before, in "widget.cpp"

#include "gadget.h"

#include

#include

struct Widget::Impl { // as before, definition of

std::string name; // Widget::Impl

std::vector data;

Gadget g1, g2, g3;

};

Widget::Widget() // as before

: pImpl(std::make_unique()) {}

Widget::~Widget() // ~Widget definition

{}

This works well, and it requires the least typing, but if you want to emphasize that the compiler-generated destructor would do the right thing — that the only reason you declared it was to cause its definition to be generated in Widget's implementation file, you can define the destructor body with “ = default”:

Widget::~Widget() = default;// same effect as above

Classes using the Pimpl Idiom are natural candidates for move support, because compiler-generated move operations do exactly what's desired: perform a move on the underlying std::unique_ptr. As Item 17explains, the declaration of a destructor in Widgetprevents compilers from generating the move operations, so if you want move support, you must declare the functions yourself. Given that the compiler-generated versions would behave correctly, you're likely to be tempted to implement them as follows:

class Widget { // still in

public: // "widget.h"

Widget();

~Widget();

Widget(Widget&& rhs) = default; // right idea,

Widget& operator=(Widget&& rhs) = default;// wrong code!

private: // as before

struct Impl;

std::unique_ptr pImpl;

};

This approach leads to the same kind of problem as declaring the class without a destructor, and for the same fundamental reason. The compiler-generated move assignment operator needs to destroy the object pointed to by pImplbefore reassigning it, but in the Widgetheader file, pImplpoints to an incomplete type. The situation is different for the move constructor. The problem there is that compilers typically generate code to destroy pImplin the event that an exception arises inside the move constructor, and destroying pImplrequires that Implbe complete.

Because the problem is the same as before, so is the fix — move the definition of the move operations into the implementation file:

class Widget { // still in "widget.h"

public:

Widget();

~Widget();

Widget(Widget&& rhs); // declarations

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

Интервал:

Закладка:

Сделать

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

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


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

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

x