Cynosure对《Effective Modern C++》的笔记(2)

Cynosure
Cynosure (我是一只橘)

想读 Effective Modern C++

Effective Modern C++
  • 书名: Effective Modern C++
  • 作者: Scott Meyers
  • 副标题: 42 Specific Ways to Improve Your Use of C++11 and C++14
  • 页数: 320
  • 出版社: O'Reilly Media
  • 出版年: 2014-12
  • 第1页

    Errata: http://www.aristeia.com/BookErrata/emc++-errata.html

    Item2

    int x1 = 27;

    int x2(27);

    int x3 = { 27 };

    int x4{ 27 };

    auto x1 = 27; // type is int, value is 27

    auto x2(27); // ditto

    auto x3 = { 27 }; // type is std::initializer_list<int>,value is { 27 }

    auto x4{ 27 }; // ditto

    Item 5: Prefer auto to explicit type declarations

    auto variables have their type deduced from their initializer, so they must be initial‐ized.

    auto x2; // error! initializer required

    auto的优点:

    - std::function approach is generally bigger and slower than the auto approach, and it mayyield out-of-memory exceptions, too.

    -写法更简洁

    - 避免“type shortcuts.”。例如unsigned sz = v.size();和for (const std::pair<std::string, int>& p : m){}

    - auto types automatically change if the type of their initializing expressionchanges, and that means that some refactorings are facilitated by the use of auto。

    auto的缺点:

    - item 2,item6

    - Some developers are disturbed by the fact that using auto eliminates the ability todetermine an object’s type by a quick glance at the source code.

    。item6

    “invisible” proxy classes don’t play well with auto. You therefore want to avoid code of this form:

    auto someVar = expression of "invisible" proxy class type

    Given double calcEpsilon();

    float ep = calcEpsilon(); // this is not preferred

    auto ep = static_cast<float>(calcEpsilon()); // this is preferred. (The explicitly typed initializer idiom)

    .

    .

    Item 7: Distinguish between () and {} when creatingobjects.

    ():parentheses(简记为parens)

    {}: braces

    std::vector<int> v{ 1, 3, 5 }; // v's initial content is 1, 3, 5

    class Widget {…

    private:

    int x{ 0 }; // fine, x's default value is 0

    int y = 0; // also fine

    int z(0); // error!

    };

    .

    uncopyable objects (e.g., std::atomics—see Item 40) may beinitialized using braces or parentheses, but not using “=”:

    std::atomic<int> ai1{ 0 }; // fine

    std::atomic<int> ai2(0); // fine

    std::atomic<int> ai3 = 0; // error!

    .

    braced initialization is that it prohibits implicit narrowing conver‐sions among built-in types:

    double x, y, z;

    int sum1{ x + y + z }; // error! sum of doubles may not be expressible as int

    Widget w2(); // most vexing parse! declares a function named w2 that returns a Widget!

    Widget w3{}; // calls Widget ctor with no args

    The drawback to braced initialization,易混淆。

    例子:

    class Widget {

    public:

    Widget(int i, bool b); // ctors not declaring

    Widget(int i, double d); // std::initializer_list params

    。。。

    };

    Widget w1(10, true); // calls first ctor

    Widget w2{10, true}; // also calls first ctor

    Widget w3(10, 5.0); // calls second ctor

    Widget w4{10, 5.0}; // also calls second ctor

    例子:

    class Widget {

    public:

    Widget(int i, bool b); // as before

    Widget(int i, double d); // as before

    Widget(std::initializer_list<long double> il); // added

    };

    Widget w1(10, true); // uses parens and, as before,calls first ctor

    Widget w2{10, true}; // uses braces, but now calls std::initializer_list ctor (10 and true convert to long double)

    Widget w3(10, 5.0); // uses parens and, as before, calls second ctor

    Widget w4{10, 5.0}; // uses braces, but now calls std::initializer_list ctor (10 and 5.0 convert to long double)

    例子:

    class Widget {

    public:Widget(int i, bool b); // as before

    Widget(int i, double d); // as before

    Widget(std::initializer_list<long double> il); // as before

    operator float() const; // convert to float

    };

    Widget w5(w4); // uses parens, calls copy ctor

    Widget w6{w4}; // uses braces, calls std::initializer_list ctor (w4 converts to float, and float converts to long double)

    Widget w7(std::move(w4)); // uses parens, calls move ctor

    Widget w8{std::move(w4)}; // uses braces, calls std::initializer_list ctor(for same reason as w6)

    例子:

    class Widget {

    public:

    Widget(int i, bool b); // as before

    Widget(int i, double d); // as before

    Widget(std::initializer_list<bool> il); // element type is now bool

    …//no implicit conversion funcs

    };

    Widget w{10, 5.0}; // error! requires narrowing conversions

    例子:

    class Widget {public:

    Widget(int i, bool b); // as before

    Widget(int i, double d); // as before

    Widget(std::initializer_list<std::string> il);//std::initializer_list element type is now std::string

    … // no implicit conversion funcs

    };

    Widget w1(10, true); // uses parens, still calls first ctor

    Widget w2{10, true}; // uses braces, now calls first ctor

    Widget w3(10, 5.0); // uses parens, still calls second ctor

    Widget w4{10, 5.0}; // uses braces, now calls second ctor

    例子:

    class Widget {public:

    Widget(); // default ctor

    Widget(std::initializer_list<int> il); // std::initializer_list ctor

    … // no implicit conversion funcs

    };

    Widget w1; // calls default ctor

    Widget w2{}; // also calls default ctor

    Widget w3(); // most vexing parse! declares a function!

    Widget w4({}); // calls std::initializer_list ctor with empty list

    Widget w5{{}}; // constructor for w5 is called with a one-element std::initializer_list, not an empty one. For details, consult this blog post(http://scottmeyers.blogspot.com/2016/11/help-me-sort-out-meaning-of-as.html).

    例子:

    std::vector<int> v1(3, 4);// [4, 4, 4]

    std::vector<int> v1{3, 4};// [3, 4]

    There are two primary take‐aways from this discussion.

    First, as a class author, you need to be aware that if yourset of overloaded constructors includes one or more functions taking a std::initializer_list, client code using braced initialization may see only the std::initializer_list overloads.

    Second, as a class client, you must choose carefully between paren‐theses and braces when creating objects. Most developers...... On the other hand, .....There is no consensus that eitherapproach is better than the other, so my advice is to pick one and apply it consistently.

    If you’re a template author, .....The author of doSomeWork can’t know. Onlythe caller can. This is precisely the problem faced by the Standard Library functionsstd::make_unique and std::make_shared (see Item 21). These functions resolvethe problem by internally using parentheses and by documenting this decision as partof their interfaces.

    .

    Item 8

    In c++98:

    void f(int); // three overloads of f

    void f(bool);

    void f(void*);

    f(0); // calls f(int), not f(void*)

    f(NULL); // might not compile, but typically calls f(int). Never calls f(void*)

    .

    nullptr’s advantage :

    1.it doesn’t have an integral type, it doesn’t have a pointer type, nullptr’s actual type is std::nullptr_t. e.g.

    f(nullptr); // calls f(void*) overload

    2.improve code clarity,

    2.1when autovariables are involved,

    e.g.

    auto result = findRecord( /* arguments */ );

    if (result == nullptr) // rather than using (result == 0)

    {…}

    2.2when templates enter the picture

    e.g.

    int f1(std::shared_ptr<Widget> spw); // call these only when the appropriate mutex is locked

    double f2(std::unique_ptr<Widget> upw); //

    bool f3(Widget* pw); //

    std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3

    decltype(auto) lockAndCall(FuncType func, MuxType& mutex,PtrType ptr)

    auto result1 = lockAndCall(f1, f1m, 0); // error

    auto result2 = lockAndCall(f2, f2m, NULL); // error

    auto result3 = lockAndCall(f3, f3m, nullptr); // fine

    The fact that template type deduction deduces the “wrong” types for 0 and NULL is the most compelling reason to use nullptr instead of 0 or NULL when you want to refer to a null pointer. With nullptr, templates pose no special challenge. Combined with the fact that nullptr doesn’t suffer from the overload resolution surprises that 0 and NULL are susceptible to, the case is ironclad. When you want to refer to a null pointer, use nullptr, not 0 or NULL

    .

    Item 9: Prefer alias declarations to typedef s

    alias declarations may be templatized(called alias templates), while typedefs cannot.

    With an alias template:

    template<typename T>

    using MyAllocList = std::list<T, MyAlloc<T>>;

    // client code

    MyAllocList<Widget> lw;

    template<typename T>

    class Widget {

    private:

    MyAllocList<T> list;// non-dependent type

    };

    With a typedef:

    template<typename T>

    struct MyAllocList {

    typedef std::list<T, MyAlloc<T>> type;

    };

    // client code

    MyAllocList<Widget>::type lw;

    template<typename T>

    class Widget {

    private:

    typename MyAllocList<T>::type list;// Compiler can’t know for sure that it names a type

    };

    .

    std::remove_const<T>::type // yields T from const T

    std::remove_reference<T>::type // yields T from T& and T&&

    std::add_lvalue_reference<T>::type // yields T& from T

    .

    alias templates are better than type synonym technology

    std::remove_const<T>::type // C++11: const T → T

    std::remove_const_t<T> // C++14 equivalent

    std::remove_reference<T>::type// C++11: T&/T&& → T

    std::remove_reference_t<T> // C++14 equivalent

    std::add_lvalue_reference<T>::type// C++11: T → T&

    std::add_lvalue_reference_t<T> // C++14 equivalent

    .

    Item 10: Prefer scoped enum s to unscoped enum s.

    scoped enums: enum class

    In C++11:

    enum class Color { black, white, red };// black, white, red are scoped to Color

    auto white = false; // fine, no other "white" in scope

    Color c = white; // error! no enumerator named "white" is in this scope

    Color c = Color::white; // fine

    auto c = Color::white; // also fine (and in accord with Item 5's advice)

    scoped enums advantages:

    1. reduction in namespace pollution

    2. scoped enums are much more strongly typed.

    于此对比的是:unscoped enums implicitly convert to integral types (and, from there, to floating-point types)

    enum class Color { black, white, red };

    Color c = Color::red;

    if (c < 14.5) { }// error! can't compare Color and double

    if (static_cast<double>(c) < 14.5) {}// odd code, but it's valid

    3. scoped enums may be forward-declared. the inability to forward-declare enums has drawbacks. The most notable is probably the increase in compilation dependencies.

    the underlying type for a scoped enum is always known:

    enum class Status; // forward declaration. // default underlying type is int

    enum class Status: std::uint32_t; // underlying type for Status is std::uint32_t (from <cstdint>)

    enum Color: std::uint8_t;// fwd decl for unscoped enum; underlying type is std::uint8_t

    enum class Status: std::uint32_t { good = 0, failed = 1,...}

    4.C++11’s std::tuples

    using UserInfo = std::tuple<std::string, std::string, std::size_t> ;

    UserInfo uInfo;

    auto val = std::get<1>(uInfo); // get value of field 1

    v.s.

    enum UserInfoFields { uiName, uiEmail, uiReputation };

    uto val = std::get<uiEmail>(uInfo); //ah, get value of email field

    5. return the enum’s underlying type.

    为了能写出这样的代码:

    auto val = std::get<toUType(UserInfoFields::uiEmail)>(uInfo);

    需要实现函数toUType(...):

    template<typename E>

    constexpr typename std::underlying_type<E>::type

    toUType(E enumerator) noexcept{

    return static_cast<typename std::underlying_type<E>::type>(enumerator);

    }

    //在C++14可简化为:

    template<typename E>

    constexpr std::underlying_type_t<E>

    toUType(E enumerator) noexcept{

    return static_cast<std::underlying_type_t<E>>(enumerator);

    }

    或更简化为:

    template<typename E>

    constexpr auto toUType(E enumerator) noexcept{

    return static_cast<std::underlying_type_t<E>>(enumerator);

    }

    .

    Item 11: Prefer deleted functions to private undefined ones.

    //C++98

    template <class charT, class traits = char_traits<charT> >

    class basic_ios : public ios_base {

    public:…

    private:

    basic_ios(const basic_ios& ); // not defined

    basic_ios& operator=(const basic_ios&); // not defined

    };

    //c++11

    template <class charT, class traits = char_traits<charT> >

    class basic_ios : public ios_base {

    public:

    basic_ios(const basic_ios& ) = delete;

    basic_ios& operator=(const basic_ios&) = delete;

    };

    Why deleted functions are declared public? Because When client code tries to use a member function, C++ checks accessibility before deleted status. When client code tries to use a deleted private function, some compilers complain only about the function being private, even though the function’s accessibility doesn’t really affect whether it can be used.

    the advantages of deleted functions:

    1. code that’s in member and friend functions will fail to compile if it tries to copy basic_ios objects. That’s an improvement over the C++98 behavior, where such improper usage wouldn’t be diagnosed until link-time.

    2.(any function may be deleted, while only member functions may be private.)

    bool isLucky(int number); // original function

    bool isLucky(char) = delete; // reject chars

    bool isLucky(bool) = delete; // reject bools

    bool isLucky(double) = delete; // reject doubles and floats

    3.prevent use of template instantiations that should be disabled. (private member functions can’t). if you have a function template inside a class, and you’d like to disable some instantiations by declaring them private (à la classic C++98 convention), you can’t, because it’s not possible to give a member function template specialization a different access level from that of the main template.

    class Widget {public:

    template<typename T> void processPointer(T* ptr) { … }

    private:

    template<> void processPointer<void>(void*); // error!

    };

    template<> void Widget::processPointer<void>(void*) = delete; // still public, but deleted

    ..

    void* pointers: there is no way to dereference them, to increment or decrement them, etc

    char* pointers: they typically represent pointers to C-style strings, not pointers to individual characters

    .

    Item 12: Declare overriding functions override.

    class Widget {

    public:

    void doWork() &; // this version of doWork applies only when *this is an lvalue

    void doWork() &&; // this version of doWork applies only when *this is an rvalue

    };

    Widget makeWidget(); // factory function (returns rvalue)

    Widget w; // normal object (an lvalue)

    w.doWork(); // calls Widget::doWork for lvalues (i.e., Widget::doWork &)

    makeWidget().doWork(); // calls Widget::doWork for rvalues (i.e., Widget::doWork &&)

    .

    class Widget {

    public:

    using DataType = std::vector<double>;

    DataType& data() &{ return values; } // for lvalue Widgets, return lvalue

    DataType data() && { return std::move(values); } // for rvalue Widgets, return rvalue

    private:

    DataType values;

    };

    auto vals1 = w.data(); // calls lvalue overload for Widget::data, copy-constructs vals1

    auto vals2 = makeWidget().data(); // calls rvalue overload for Widget::data, move-constructs vals2

    .

    Item 13: Prefer const_iterators to iterators.

    const_iterators simply don’t convert to iterators. That’s not a C++98 restriction. It’s true in C++11, too. const.

    std::vector<int> values;

    std::vector<int>::iterator it = std::find(values.begin(),values.end(), 1983); // in C++98

    values.insert(it, 1998);

    auto it = std::find(values.cbegin(),values.cend(), 1983); // In C++11, use cbegin and cend

    values.insert(it, 1998);

    .

    // C++14

    template<typename C, typename V>

    void findAndInsert(C& container, const V& targetVal, const V& insertVal) // in container, find first occurrence of targetVal, then insert insertVal there

    {

    using std::cbegin; using std::cend;

    auto it = std::find(cbegin(container), cend(container), targetVal);// non-member cbegin non-member cend

    container.insert(it, insertVal);

    }

    .

    // C++11, write your own non-member cbegin(...)

    template <class C>

    auto cbegin(const C& container)->decltype(std::begin(container))

    {

    return std::begin(container); // Invoking the nonmember begin function (provided by C++11) on a const container yields a const_iterator

    }

    .

    Item 14: Declare functions noexcept if they won’t emit exceptions

    In C++11, unconditional noexcept is for functions that guarantee they won’t emit exceptions

    Advantages of adding noexcept to a function which won’t emit an exception:

    - it is a good interface specification.

    - it permits compilers to generate better object code:

    1.

    int f(int x) throw(); // no exceptions from f: C++98 style. the call stack is unwound to f’s caller, and, after some actions not relevant here, program execution is terminated. less optimizable.

    int f(int x) noexcept; // no exceptions from f: C++11 style. the stack is only *possibly* unwound before program execution is terminated. most optimizable.

    int f(int x) // less optimizable

    2.

    In C++11, a natural optimization would be to replace the copying of std::vector elements with moves. 但如果move了n个元素后,在move第n+1个元素时抛出异常。此时无法回退至move前的状态(因为n个元素已经被move了)。这种情况无解。因此,C++11 implementations can’t silently replace copy operations inside push_back with moves unless it’s known that the move operations won’t emit exceptions。In that case, having moves replace copies would be safe(不会产生上述问题), and the only side effect would be improved performance(因为被move替代).

    std::vector::push_back, std::vector::reserve, std::deque::insert, etc. All these functions replace calls to copy operations in C++98 with calls to move operations in C++11 only if the move operations are known to not emit exceptions.

    3.

    template <class T, size_t N>

    void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));

    Exception-neutral functions are never noexcept

    Twisting a function’s implementation to permit a noexcept declaration 是不可取的

    By default, all memory deallocation functions and all destructors—both user-defined and compilergenerated—are implicitly noexcept. There’s thus no need to declare them noexcept.(Doing so doesn’t hurt anything, it’s just unconventional.)

    functions with wide contracts:Such a function may be called regardless of the state of the program, and it imposes no constraints on the arguments that callers pass it. Functions with wide contracts never exhibit undefined behavior. declaring wide contracts functions as noexcept

    functions with narrow contracts:Functions without wide contracts have narrow contracts. For such functions, if a precondition is violated, results are undefined.

    .

    Item 15: Use constexpr whenever possible

    translation = compilation + linking.

    all constexpr objects are const, but not all const objects are constexpr.

    constexpr functions: it says that if input parameters are compile-time constants, pow’s result may be used as a compile-time constant. If input parameters are not compile-time constants, the result will be computed at runtime.

    some computations traditionally done at runtime can migrate to compile time. The more code taking part in the migration, the faster your software will run. (Compilation may take longer, however.)

    in C++11, constexpr member functions are implicitly const.

    .

    Item 16: Make const member functions thread safe.

    const+mutable has a problem in thread context. This problem can be resovled by employing mutex. But the whole class object will become move-only object because mutex is move-only.

    .

    Item 17: Understand special member function generation.

    class Widget {

    public:

    Widget(Widget&& rhs); // move constructor

    Widget& operator=(Widget&& rhs); // move assignment operator

    };

    the move constructor move-constructs each nonstatic data member of the class from the corresponding member of its parameter rhs, and the move assignment operator move-assigns each non-static data member from its parameter. The move constructor also move-constructs its base class parts (if there are any), and the move assignment operator move-assigns its base class parts.

    a memberwise move consists of move operations on data members and base classes that support move operations.

    move constructor <--> move assignment operator, 声明其中一个,就会让编译器不产生另一个.

    copy operation (construction or assignment)<-->move operations (construction or assignment), 声明其中一个,就会让编译器不产生另一个

    The Rule of Three states that if you declare any of a copy constructor, copy assignment operator, or destructor, you should declare all three.

    So move operations are generated for classes (when needed) only if these three things are true:

    • No copy operations are declared in the class.

    • No move operations are declared in the class.

    • No destructor is declared in the class.

    in C++11, declaring copy operations or a destructor --> not automatically generate copy operations.

    So if your code depends on the generation of copy operations. you should use '=default'.

    class Base

    {

    public:

    virtual ~Base() = default; // make dtor virtual。若自定义destructor,则不会生成move operations。

    Base(Base&&) = default; // support moving。所以如果想支持move operations,就需要添加“= default”

    Base& operator=(Base&&) = default;

    Base(const Base&) = default; // support copying。Declaring the move operations disables the copy operations, 所以如果想支持copyability,就需要添加“= default”

    Base& operator=(const Base&) = default;

    };

    如果为class添加了destructor,则不会生成move operations。则client code里的move操作会变成copy操作,这有损性能。解决方法是为the copy and move operations添加“= default”

    Destructor:

    is noexcept by default。

    Copy constructor:

    Deleted if the class declares a move operation. Generation of this function in a class with a user-declared copy assignment operator or destructor is deprecated.

    Copy assignment operator:

    Generated only if the class lacks a user-declared copy assignment operator.

    Deleted if the class declares a move operation.

    Generation of this function in a class with a user-declared copy constructor or destructor is deprecated.

    Move constructor and move assignment operator:

    Generated only if the class contains no userdeclared copy operations, move operations, or destructor

    对于member function template:

    class Widget {

    template<typename T> Widget(const T& rhs);// 如果T为Widget,会怎样?见Item26

    template<typename T> Widget& operator=(const T& rhs);// 如果T为Widget,会怎样?见Item26

    };

    Item 18: Use std::unique_ptr for exclusive-ownership resource management.

    auto delInvmt = [](Investment* pInvestment) // custom deleter(a lambdaexpression)

    {

    makeLogEntry(pInvestment);

    delete pInvestment;

    };

    //---

    template<typename... Ts>

    std::unique_ptr<Investment, decltype(delInvmt)> makeInvestment(Ts&&... params)// revised return type

    {

    std::unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt); // ptr to be returned

    if ( /* a Stock object should be created */ ){pInv.reset(new Stock(std::forward<Ts>(params)...));}

    else if ( /* a Bond object should be created */ ){pInv.reset(new Bond(std::forward<Ts>(params)...));}

    else if ( /* a RealEstate object should be created */ ){pInv.reset(new RealEstate(std::forward<Ts>(params)...));}

    return pInv;

    }

    delInvmt is the custom deleter

    auto delInvmt1 = [](Investment* pInvestment){...}

    template<typename... Ts>

    std::unique_ptr<Investment, decltype(delInvmt1)> // return type has size of Investment*

    makeInvestment(Ts&&... args);

    void delInvmt2(Investment* pInvestment) // custom deleter as function

    {

    makeLogEntry(pInvestment);

    delete pInvestment;

    }

    template<typename... Ts>

    std::unique_ptr<Investment, void (*)(Investment*)> // return type has size of Investment* + at least size of function pointer! 体积更大

    makeInvestment(Ts&&... params);

    .

    .

    std::unique_ptr<T[]> //when you’re using a C-like API that returns a raw pointer to a heap array

    std::shared_ptr<Investment> sp = makeInvestment( arguments );// converts std::unique_ptr to std::shared_ptr

    .

    .

    Item 19: Use std::shared_ptr for shared-ownership resource management.

    move construction is faster than copy construction,

    move assignment is faster than copy assignment.

    supports custom deleters, but it differs from that for std::unique_ptr.

    auto loggingDel = [](Widget *pw){ makeLogEntry(pw); delete pw; }; // custom deleter(as in Item 18)

    std::unique_ptr<Widget, decltype(loggingDel)> upw(new Widget, loggingDel); // deleter type is part of ptr type

    std::shared_ptr<Widget> spw(new Widget, loggingDel);// deleter type is not part of ptr type, this is more flexible

    pw1 = pw2; // fine, std::unique_ptrs cannot do this.

    void fool(std::shared_ptr<Widget> p); fool(pw1); // fine. std::unique_ptrs cannot do this.

    constructing more than one std::shared_ptr from a single raw pointer is BAD! like this:

    auto pw = new Widget;

    std::shared_ptr<Widget> spw1(pw, loggingDel);

    std::shared_ptr<Widget> spw2(pw, loggingDel); // this is bad

    std::shared_ptrs的性能开销:p133

    std::shared_ptrs can’t do is work with arrays。 std::shared_ptr<T[]>的缺点:p133

    Item 20: Use std::weak_ptr for std::shared_ptrlike pointers that can dangle.

    std::weak_ptrs can’t be dereferenced, nor can they be tested for nullness.

    That’s because std::weak_ptr isn’t a standalone smart pointer. It’s an augmentation of std::shared_ptr.

    std::weak_ptrs are typically created from std::shared_ptrs.

    auto spw = std::make_shared<Widget>();

    std::weak_ptr<Widget> wpw(spw);

    spw = nullptr; // RC goes to 0, and the Widget is destroyed. wpw now dangles

    std::weak_ptr --> std::shared_ptr的两种方法:

    1. std::shared_ptr<Widget> spw1 = wpw.lock(); // The std::shared_ptr is null if the wpw has expired:

    2. std::shared_ptr<Widget> spw3(wpw); // it throws std::bad_weak_ptr if wpw has expired,

    std::weak_ptr避免std::shared_ptr之间的循环

    std::weak_ptrs don’t participate in the shared ownership of objects and hence don’t affect the pointed-to object’s reference count.

    Item 21: Prefer std::make_unique and std::make_shared to direct use of new.

    ======================================================

    Things to Remember

    Item 8

    • Prefer nullptr to 0 and NULL.

    • Avoid overloading on integral and pointer types.

    Item 9: Prefer alias declarations to typedef s

    • typedefs don’t support templatization, but alias declarations do.

    • Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.

    • C++14 offers alias templates for all the C++11 type traits transformations.

    Item 10: Prefer scoped enum s to unscoped enum s.

    • C++98-style enums are now known as unscoped enums.

    • Enumerators of scoped enums are visible only within the enum. They convert to other types only with a cast.

    • Both scoped and unscoped enums support specification of the underlying type. The default underlying type for scoped enums is int. Unscoped enums have no default underlying type.

    • Scoped enums may always be forward-declared. Unscoped enums may be forward-declared only if their declaration specifies an underlying type.

    Item 11: Prefer deleted functions to private undefined ones.

    • Prefer deleted functions to private undefined ones.

    • Any function may be deleted, including non-member functions and template instantiations.

    Item 12: Declare overriding functions override.

    • Declare overriding functions override.

    • Member function reference qualifiers make it possible to treat lvalue and

    rvalue objects (*this) differently

    Item 13: Prefer const_iterators to iterators.

    • Prefer const_iterators to iterators.

    • In maximally generic code, prefer non-member versions of begin, end,

    rbegin, etc., over their member function counterparts.

    .

    Item 14:

    • noexcept is part of a function’s interface, and that means that callers may depend on it.

    • noexcept functions are more optimizable than non-noexcept functions.

    • noexcept is particularly valuable for the move operations, swap, memory deallocation functions, and destructors.

    • Most functions are exception-neutral rather than noexcept.

    .

    Item 15 constexpr

    • constexpr objects are const and are initialized with values known during compilation.

    • constexpr functions can produce compile-time results when called with arguments whose values are known during compilation.

    • constexpr objects and functions may be used in a wider range of contexts than non-constexpr objects and functions.

    • constexpr is part of an object’s or function’s interface.

    .

    Item 16

    • Make const member functions thread safe unless you’re certain they’ll never be used in a concurrent context.

    • Use of std::atomic variables may offer better performance than a mutex, but they’re suited for manipulation of only a single variable or memory location.

    Item 17: Understand special member function generation.

    • The special member functions are those compilers may generate on their own: default constructor, destructor, copy operations, and move operations.

    • Move operations are generated only for classes lacking explicitly declared move operations, copy operations, and a destructor.

    • The copy constructor is generated only for classes lacking an explicitly declared copy constructor。it’s deleted if a move operation is declared.

    The copy assignment operator is generated only for classes lacking an explicitly declared copy assignment operator, and it’s deleted if a move operation is declared.

    Generation of the copy operations in classes with an explicitly declared destructor is deprecated.

    • Member function templates never suppress generation of special member functions.

    Item 18: Use std::unique_ptr for exclusive-ownership resource management.

    • std::unique_ptr is a small, fast, move-only smart pointer for managing resources with exclusive-ownership semantics.

    • By default, resource destruction takes place via delete, but custom deleters can be specified. Stateful deleters and function pointers as deleters increase the size of std::unique_ptr objects.

    • Converting a std::unique_ptr to a std::shared_ptr is easy.

    .

    Item 19: Use std::shared_ptr for shared-ownership resource management.

    • std::shared_ptrs offer convenience approaching that of garbage collection for the shared lifetime management of arbitrary resources.

    • Compared to std::unique_ptr, std::shared_ptr objects are typically twice as big, incur overhead for control blocks, and require atomic reference count manipulations.

    • Default resource destruction is via delete, but custom deleters are supported. The type of the deleter has no effect on the type of the std::shared_ptr. • Avoid creating std::shared_ptrs from variables of raw pointer type.

    Item 20: Use std::weak_ptr for std::shared_ptrlike pointers that can dangle.

    • Use std::weak_ptr for std::shared_ptr-like pointers that can dangle.

    • Potential use cases for std::weak_ptr include caching, observer lists, and the prevention of std::shared_ptr cycles.

    Item 21: Prefer std::make_unique and std::make_shared to direct use of new.

    2018-08-04 11:15:08 回应
  • 第2页

    Things to Remember

    Item 8

    • Prefer nullptr to 0 and NULL.

    • Avoid overloading on integral and pointer types.

    Item 9: Prefer alias declarations to typedef s

    • typedefs don’t support templatization, but alias declarations do.

    • Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.

    • C++14 offers alias templates for all the C++11 type traits transformations.

    Item 10: Prefer scoped enum s to unscoped enum s.

    • C++98-style enums are now known as unscoped enums.

    • Enumerators of scoped enums are visible only within the enum. They convert to other types only with a cast.

    • Both scoped and unscoped enums support specification of the underlying type. The default underlying type for scoped enums is int. Unscoped enums have no default underlying type.

    • Scoped enums may always be forward-declared. Unscoped enums may be forward-declared only if their declaration specifies an underlying type.

    Item 11: Prefer deleted functions to private undefined ones.

    • Prefer deleted functions to private undefined ones.

    • Any function may be deleted, including non-member functions and template instantiations.

    Item 12: Declare overriding functions override.

    • Declare overriding functions override.

    • Member function reference qualifiers make it possible to treat lvalue and

    rvalue objects (*this) differently

    Item 13: Prefer const_iterators to iterators.

    • Prefer const_iterators to iterators.

    • In maximally generic code, prefer non-member versions of begin, end,

    rbegin, etc., over their member function counterparts.

    .

    Item 14:

    • noexcept is part of a function’s interface, and that means that callers may depend on it.

    • noexcept functions are more optimizable than non-noexcept functions.

    • noexcept is particularly valuable for the move operations, swap, memory deallocation functions, and destructors.

    • Most functions are exception-neutral rather than noexcept.

    .

    Item 15 constexpr

    • constexpr objects are const and are initialized with values known during compilation.

    • constexpr functions can produce compile-time results when called with arguments whose values are known during compilation.

    • constexpr objects and functions may be used in a wider range of contexts than non-constexpr objects and functions.

    • constexpr is part of an object’s or function’s interface.

    2018-08-05 12:46:59 1人喜欢 回应

Cynosure的其他笔记  · · · · · ·  ( 全部128条 )

夏日再会
1
Alternative Logics. Do Sciences Need Them?
1
Modern Classical Physics
1
中国历代军事战略(上下)
1
费恩曼物理学讲义 (第3卷)(英文版)
1
Introduction to Circle Packing
1
Trick or Truth?
2
Questioning the Foundations of Physics
1
Matrix Computations
1
沉默的大多数
1
要瘦就瘦,要健康就健康
1
Fast Fourier Transform and Its Applications
1
From Groups to Geometry and Back
1
Geometries
1
不锈时光
1
Generations
1
Geometry
1
中国国家治理的制度逻辑
1
费恩曼物理学讲义(第2卷)(英文版)
1
费恩曼物理学讲义
1
Differential Geometry
1
Applied Computational Physics
1
Make Your Own Neural Network
1
龙与鹰的帝国
1
巨婴国
1
An Introduction to Manifolds
1
Generalized Curvatures (Geometry and Computing)
1
求索中国
1
Statistical Mechanics
1
Statistical Mechanics
1
The Probability Lifesaver
1
An Introduction to Thermal Physics
1
Modern Approaches to Discrete Curvature
1
Discrete Differential Geometry
1
Visual Complex Analysis
1
The Algorithmic Beauty of Sea Shells
1
The Algorithmic Beauty of Seaweeds, Sponges and Corals
1
The Algorithmic Beauty of Plants
1
致女儿书
1
八十年代中学生
1
毛以后的中国1976-1983
1
The Rise and Fall of the Third Reich
1
Are Leaders Born or Are They Made?
1
光荣与梦想
1
文明的度量
1
Introduction to Quantum Mechanics
1
Waves
1
美国宪政历程
1
Electricity and Magnetism
1
Mechanics (Berkeley Physics Course, Vol. 1)
1
An Introduction to Systems Biology
1
Mathematical Physics
1
Sapiens
1
哲学家们都干了些什么?
1
Fractional Calculus
1
七缀集
1
Polygon Mesh Processing
1
Fractional Calculus View of Complexity
1
Discrete Calculus
1
Perfectly Reasonable Deviations from the Beaten Track
1
A Student's Guide to Maxwell's Equations
1
A Student's Guide to Vectors and Tensors
1
Physics from Symmetry
1
Algebra
1
控制论与科学方法论
1
量子理论
1
Contemporary Abstract Algebra
1
Abstract Algebra(Second Edition)
1
Conscious Loving
1
常微分方程教程
1
Ordinary Differential Equations
1
A Geometric Approach to Differential Forms
1
Differential Geometry of Curves and Surfaces
2
Geometry and the Imagination
1
Differential Geometry
1
Numerical Analysis
1
科学计算导论
1
生物数学趣谈
1
Discovering Modern Set Theory. I: The Basics
1
微积分学教程(第3卷)
3
Historical Dynamics
1
Elementary Calculus
1
超实讲义
1
Vector Calculus
1
微积分学教程(第2卷)
1
文明的进程
1
Digital Lighting and Rendering
1
The VES Handbook of Visual Effects
6
洗脑术
1
The Python Standard Library by Example
1
数学概观
1
数学的统一性
1
好妈妈胜过好老师
1
食品真相大揭秘
1
The Illusion of Life
1
全球通史
5
全球通史
5
变态心理学
2
艺术与癫狂
1
API Design for C++
5
内向者优势
2
维特根斯坦传
1
月亮和六便士
1