Oct 4, 2015

[C++] Cpp Core Guidelines, excerpts that I might overlook.

https://github.com/isocpp/CppCoreGuidelines



array_view  // void copy(array_view<const T> r, array_view<T> r2); // copy r to r2
            // void copy_n(array_view<const T> p, array_view<T> q); // copy from p to q
string_view

owner<>
not_null<> // int length(not_null<const char*> p);
zstring  // Use zstring and czstring to represent a C-style, zero-terminated strings.

Expects  // Prefer Expects() for expressing preconditions
Ensures  // Post condition


----------------
[[lifetime(this)]]








1.
Sometype iter;                                          // default initialize if we haven't already
Someothertype success;                                  // used these variables for some other purpose

tie( iter, success ) = myset.insert( "Hello" );         // normal return value
if (success) do_something_with( iter );

In some cases it may be useful to return a specific,
user-defined Value_or_error type along the lines of variant<T, error_code>,
rather than using the generic tuple.



2.
回傳 ptr 只有在回傳 position of a container or nullptr.



3.
class Handle {      // OK
    owner<Shape&> s;    // use reference rather than pointer to prevent rebinding
    // ...
public:
    Handle(Shape& ss) : s{ss} { /* ... */ }
    ~Handle() { delete &s; }
    // ...
};

對ref取址 就是 該 ref 真正reference到的object的位址。 等同於ptr本身。



4.
struct Rec2{
    string s;
    int i;
    Rec2(const string& ss, int ii = 0) :s{ss}, i{ii} {}     // redundant
};

POD可用 Type{a,b,c} 順序初始化內部的變數。


5.
By default, declare single-argument constructors explicit


6.
Use inheriting constructors to import constructors into a derived class that does not need further explicit initialization

class Rec {
    // ... data and lots of nice constructors ...
};

class Oper : public Rec {
    using Rec::Rec;
    // ... no data members ...
    // ... lots of nice utility functions ...
};


7.
Avoid self-assign check, let the library type do it by itself.

Foo& Foo::operator=(const Foo& a)   // OK, but there is a cost
{
    if (this==&a) return *this; // REMOVE THIS LINE!!!!
    s = a.s;  // if it's self-assign, it's ok, library type cope with this issue.
    i = a.i;
    return *this;
}



8.
For value-like types, consider providing a noexcept swap function

9.
Make == symmetric with respect to operand types and noexcept


10.
Make < symmetric with respect to operand types and noexcept


11.
Make a hash noexcept


12.
Use abstract classes as interfaces when complete separation of interface and implementation is needed.
Such as on an ABI (link) boundary.


13.
Redefine or prohibit copying for a base class; prefer a virtual clone function instead.

Copying a base is usually slicing. If you really need copy semantics, 
copy deeply: Provide a virtual clone function that will copy the actual most-derived type,
and in derived classes return the derived type (use a covariant return type).


14.
Ensure all data members have the same access level


15.
Use multiple inheritance to represent multiple distinct interfaces

16.
Like other casts, dynamic_cast is overused. Prefer virtual functions to casting. 
Prefer static polymorphism to hierarchy navigation where it is possible (no run-time resolution necessary) and reasonably convenient.


17.
Define operations on enumerations for safe and simple use


18.
Don't use ALL_CAPS for enumerators// clash with MACRO

19.
void fun( shared_ptr<Widget> sp1, shared_ptr<Widget> sp2 );

This fun can be called like this:

fun( shared_ptr<Widget>(new Widget(a, b)), shared_ptr<Widget>(new Widget(c, d)) );  // BAD: potential leak


20.
void sink(unique_ptr<widget>); // consumes the widget

void sink(widget*);             // just uses the widget


21.
void share( shared_ptr<widget> );            // share – "will" retain refcount

void reseat( shared_ptr<widget>& );          // "might" reseat ptr

void may_share( const shared_ptr<widget>& ); // "might" retain refcount


22.
void reseat( unique_ptr<widget>& ); // "will" or "might" reseat pointer

BAD:
void thinko( const unique_ptr<widget>& ); // usually not what you want


23.
Keep common and local names short, and keep uncommon and nonlocal names longer

24.
Don't make claims about performance without measurements


25.
ccess memory predictably

Reason

Performance is very sensitive to cache performance and cache algorithms favor simple (usually linear) access to adjacent data.

Example

int matrix[rows][cols];

//bad
for(int c=0; c<cols; ++c)
    for(int r=0; r<rows; ++r)
        sum += matrix[r][c];

//good
for(int r=0; r<rows; ++r)
    for(int c=0; c<cols; ++c)
        sum += matrix[r][c];
        
        
26.
State your preconditions
State your postconditions

27.
Destructors, deallocation, and swap must never fail


28.
Use a final_action object to express cleanup if no suitable resource handle is available

Reason:

finally is less verbose and harder to get wrong than try/catch.

Example

void f(int n)
{
    void* p = malloc(1, n);
    auto _ = finally([p] { free(p); });
    // ...
}

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.