1. 程式人生 > 實用技巧 >讀書筆記 《Effective modern C++》之 Moving to Modern C++(三)

讀書筆記 《Effective modern C++》之 Moving to Modern C++(三)

Item 13: 優先使用const_iterators而不是iterators

使用cbegin和cend(c++11)。

// in container, find first occurrence of targetVal, then insert insertVal there
template<typename C, typename V>
void findAndInsert(C& container,  const V& targetVal, const V& insertVal)
{ 
      using std::cbegin;
      using std::cend;
      auto it = std::find(cbegin(container), // non-member cbegin
                          cend(container),   // non-member cend
                          targetVal);
      container.insert(it, insertVal);
}

自由函式cbegin和cend需要c++14。在c++11的代替方案是

template <class C>
auto cbegin(const C& container)->decltype(std::begin(container))
{
      return std::begin(container);
}

雖然c++11可以使用成員函式版本的cbegin,但是container是一個const的物件,因此使用begin也是返回的const_iterator,但不是每個容器都有成員函式版的cbegin。begin有陣列特化的版本。

Item 14: 如果函式不會丟擲異常,就要申明noexcept

根據函式是否有noexcept可以進行不同的操作(call不同的函式,或者說編譯器對noexcept做更激進的優化),來達到優化的效果。

int f(int x) throw();   // C++98 style
int f(int x) noexcept;  // C++11 style
  • noexcept讓編譯器生成更好的目的碼

在沒有noexcept的情況下,如果出現異常,呼叫棧會展開到函式f的caller,再進行一些無關的操作,然後結束程式。而又noexcept的棧只需要再執行結束時候才展開。因此帶noexpect的函式的目的碼可以不帶有處理棧展開的程式碼。

the call stack is unwound to f’s caller, and, after some actions not relevant here, program execution is terminated. With the C++11 exception specification, runtime behaviour is slightly different: the stack is only possibly unwound before program execution is terminated.

  • 根據是否noexcept決定呼叫行為
std::vector<Widget> vw;
Widget w;
vw.push_back(w);

典型的函式有std::move_if_noexcept。在vector中的成員函式push_back,在容器記憶體滿了時候會再申請一塊記憶體,因此需要對異常安全進行保證:往新的記憶體拷貝元素時,如果有異常丟擲,vector的成員應該不變,因為直到全部元素被成功拷貝之前,舊地址的元素都不改變。但是把一個物件從就記憶體move到新記憶體上時可能丟擲異常,而一但發生,就沒法恢復成原先的狀態了,所以只有保證移動建構函式為noexcept時候push_back才會使用move。

https://en.cppreference.com/w/cpp/container/vector/push_back

  • 三種noexcept的用法
template <typename T, size_t N>
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));

template <typename T1, typename T2>
struct pair {
    //...
    void swap(pair& p) noexcept(noexcept(swap(first, p.first)) &&
                                noexcept(swap(second, p.second)));
    // ...
};

Item 15: 儘可能地使用constexpr

Item 16: Make const member functions thread safe.

Item 17: Understand special member function generation