中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

java web網(wǎng)站開發(fā)流程廈門人才網(wǎng)最新招聘信息網(wǎng)

java web網(wǎng)站開發(fā)流程,廈門人才網(wǎng)最新招聘信息網(wǎng),網(wǎng)站建設屬于辦公費嗎,騰訊企點怎么群發(fā)這一部分介紹C17對已有標準庫組件的拓展和修改。 1. 類型特征拓展 1.1 類型特征后綴_v 自從C17起&#xff0c;對所有返回值的類型特征使用后綴_v&#xff0c;例如&#xff1a; std::is_const_v<T>; // C17 std::is_const<T>::value; // C11這適用于所有返回值的…

這一部分介紹C++17對已有標準庫組件的拓展和修改。

1. 類型特征拓展

1.1 類型特征后綴_v

自從C++17起,對所有返回值的類型特征使用后綴_v,例如:

std::is_const_v<T>; // C++17
std::is_const<T>::value; // C++11

這適用于所有返回值的類型特征,也可以用作運行時的條件表達式。

1.2 新的類型特征
特征效果
is_aggregate是否是聚合體類型
is_swappable該類型是否能調(diào)用swap()
is_nothrow_swapable該類型是否能調(diào)用swap()并且不會拋出異常
is_swappable_with<T1,T2>特定的兩個類型是否能交換(swap())
is_nothrow_swappable_with<T1,T2>特定的兩個類型是否能交換(swap())并不會拋出異常
has_unique_object_representations是否該類型的兩個值相等的對象在內(nèi)存中的表示也一樣
is_invocable<T,Args…>是否可以用Args...調(diào)用
is_nothrow_invocable<T,Args…>是否可以用Args...調(diào)用并不會拋出異常
is_invocable_r<RT,T,Args…>該類型是否可以用Args...調(diào)用,且返回RT類型
is_nothrow_invocable_r<RT,T,Args…>該類型是否可以用Args...調(diào)用,且返回RT類型并且不會拋出異常
invoke_result<T,Args…>Args...作為實參進行調(diào)用會返回的類型
conjunction<B…>對bool特征B...進行邏輯與
disjunction<B…>對bool特征B...進行邏輯或運算
negation對bool特征B進行非運算
is_execution_policy是否執(zhí)行策略類型

另外,is_literal_type<>result_of<>自從C++17起被廢棄。

template<typename T>
struct D : string, complex<T>
{string data;
};struct C
{bool operator()(int) const{return true;}
};string foo(int);using T1 = invoke_result_t<decltype(foo), int>; // string// 是否是指針
template<typename T>
struct IsPtr : disjunction<is_null_pointer<T>, // 空指針is_member_pointer<T>, // 成員函數(shù)指針is_pointer<T>> // 原生指針
{};int main()
{D<float> s{ {"hello"},{4.5,6.7},"world" };cout << is_aggregate_v<decltype(s)> << endl; // 1cout << is_swappable_v<int> << endl; // 1cout << is_swappable_with_v<int, int> << endl; // 1cout << is_invocable_v<C> << endl; // 0cout << is_invocable_v<C,int> << endl; // 1cout << is_invocable_v<int(*)()> << endl; // 1cout << is_invocable_r_v<bool, C, int> << endl; // 1}

2. 并行STL算法

為了從現(xiàn)代的多核體系中受益,C++17標準庫引入了并行STL算法來使用多個線程并行處理元素。

許多算法擴展了一個新的參數(shù)來指明是否要并行運行算法。

一個簡單的計時器輔助類

設計一個計算器來測量算法的速度。

#include <chrono>/*****************************************
* timer to print elapsed time
******************************************/class Timer
{
private:chrono::steady_clock::time_point last;
public:Timer() : last{ chrono::steady_clock::now() }{}void printDiff(const std::string& msg = "Timer diff: "){auto now{ chrono::steady_clock::now() };chrono::duration<double, milli> diff{ now - last };cout << msg << diff.count() << "ms\n";last = chrono::steady_clock::now();}
};
2.1 使用并行算法
2.1.1 使用并行的for_each()
#include <numeric>
#include <execution> // 執(zhí)行策略,包含并行模式
#include <cmath>int main()
{int numElems = 1000000;struct Data{double value; // 初始值double sqrt;  // 計算平方根};// 初始化numElems個還沒有計算平方根的值vector<Data> coll;coll.reserve(numElems);for (int i = 0; i < numElems; ++i)coll.push_back(Data{ i * 4.37,0 });for (int i = 0; i < 5; ++i){Timer t;// 順序計算平方根for_each(execution::seq, coll.begin(), coll.end(), [](auto& val){val.sqrt = sqrt(val.value);});t.printDiff("sequential: ");// 并行計算平方根for_each(execution::par, coll.begin(), coll.end(), [](auto& val){val.sqrt = sqrt(val.value);});t.printDiff("parallel: ");cout << endl;}
}

測試結果中,只有少量元素的時候,串行算法明顯快得多。這是因為啟動和管理線程占用了太多的事件。但是當元素很大的時候,并行執(zhí)行的效率就大大提升。

值得使用并行算法的關鍵在于:

  • 操作很長(復雜)
  • 有很多元素
2.1.2 使用并行sort()

排序是另一個并行算法的例子。

int main()
{int numElems = 100000;vector<string> coll;for (int i = 0; i < numElems / 2; ++i){coll.emplace_back("id" + to_string(i));coll.emplace_back("ID" + to_string(i));}for (int i = 0; i < 5; ++i){Timer t;// 順序排序sort(execution::seq, coll.begin(), coll.end(), [](const auto& a,const auto& b){return string_view{ a }.substr(2) < string_view{ b }.substr(2);});t.printDiff("sequential: ");// 并行排序sort(execution::par, coll.begin(), coll.end(), [](const auto& a, const auto& b){return string_view{ a }.substr(2) < string_view{ b }.substr(2);});t.printDiff("parallel: ");// 并行化亂序排序sort(execution::par_unseq, coll.begin(), coll.end(), [](const auto& a, const auto& b){return string_view{ a }.substr(2) < string_view{ b }.substr(2);});t.printDiff("parallel unsequential: ");cout << endl;}
}
2.2 執(zhí)行策略

你可以像并行STL算法傳遞不同的執(zhí)行策略作為第一個參數(shù)。定義在頭文件<execution>中。

策略含義
std::execution::seq順序執(zhí)行
std::execution::par并行化順序執(zhí)行
std::execution::par_unseq并行化亂序執(zhí)行(保證不會出現(xiàn)死鎖)
2.3 異常處理

當處理元素的函數(shù)因為未捕獲的異常而退出時所有的并行算法會調(diào)用terminate()

并行算法本身也可能會拋出異常。比如它們申請并行執(zhí)行所需的臨時內(nèi)存資源時失敗了,可能會拋出bad_alloc異常。

2.4 并行算法概述

無限制的并行算法

  • find_end()adjacent_find()
  • search()search_n()
  • swap_ranges()
  • replace()replace_if()
  • fill()
  • generate()
  • remove()remove_if()unique()
  • reverse()rotate()
  • partition()stable_sort()partial_sort()
  • is_sorted()is_sorted_until()
  • nth_element()
  • inplace_merge()
  • is_heap()is_heap_until()
  • min_element()max_element()min_max_element()

無并行版本的算法

  • accmulate()
  • partial_sum()
  • inner_product()
  • search()
  • copy_backward()move_backward()
  • sample()shuffle()
  • partition_point()
  • lower_bound()upper_bound()equal_range()
  • binary_serach()
  • is_permutation()
  • next_permutation()prev_permutation()
  • push_heap()pop_hep()make_heap()sort_heap()

對于一下算法,可以使用對應的并行算法來替代:

  • accumulate(),使用reduce()或者transform_reduce()
  • inner_product(),使用transform_reduce()
2.5 并行編程的新算法的動機

C++17還引入了一些補充的算法來實現(xiàn)從C++98就可以的標準算法的并行執(zhí)行。

2.5.1 reduce()

reduceaccumulate()的并行化版本,但是也有所不同,下面分幾個場景介紹:

可結合可交換操作的并行化(例如加法):

void printSum(long num)
{vector<long> coll;coll.reserve(num * 4);for (long i = 0; i < num; ++i){coll.insert(coll.end(), { 1,2,3,4 });}Timer t;auto sum = reduce(execution::par, coll.begin(), coll.end(), 0L);t.printDiff("reduce: ");sum = accumulate(coll.begin(), coll.end(), 0L);t.printDiff("accumulate: ");cout << "sum: " << sum << endl;
}int main()
{printSum(1);printSum(1000);printSum(1000000);
}

不可交換操作的并行化(浮點數(shù)相加):

void printSum(long num)
{vector<double> coll;coll.reserve(num * 4);for (long i = 0; i < num; ++i){coll.insert(coll.end(), { 0.1,0.3,0.00001 });}Timer t;double sum1 = reduce(execution::par, coll.begin(), coll.end(), 0.0);t.printDiff("reduce: ");double sum2 = accumulate(coll.begin(), coll.end(), 0.0);t.printDiff("accumulate: ");cout << (sum1 == sum2 ? "equal\n" : "differ\n");
}int main()
{cout << setprecision(5); // 浮點數(shù)精度printSum(1);               // equalprintSum(1000);           // equalprintSum(1000000);       // differ
}

不可結合操作的并行化(累積操作改為加上每個值的平方):

void printSum(long num)
{vector<long> coll;coll.reserve(num * 4);for (long i = 0; i < num; ++i){coll.insert(coll.end(), { 1,2,3,4 });}auto squareSum = [](auto sum, auto val) {return sum + val * val;};auto sum = accumulate(coll.begin(), coll.end(), 0L, squareSum);cout << "accumulate(): " << sum << endl;auto sum1 = reduce(execution::par,coll.begin(), coll.end(), 0L, squareSum);cout << "reduce(): " << sum << endl;
}int main()
{printSum(1);printSum(1000);printSum(10000000);
}

reduce()有可能會導致結果不正確。因為這個操作是不可結合的。假設有三個元素1、2、3。在計算過程中可能導致計算的是:

(0 + 1 * 1) + (2 + 3 * 3) * (2 + 3 * 3)

解決這個問題的方法是用另一個新算法transform_reduce()。把我們對每一個元素的操作和可交換的結果的累計都并行化。

void printSum(long num)
{vector<long> coll;coll.reserve(num * 4);for (long i = 0; i < num; ++i){coll.insert(coll.end(), { 1,2,3,4 });}auto sq = [](auto val) {return val * val;};auto sum = transform_reduce(execution::par, coll.begin(), coll.end(), 0L, plus{}, sq);cout << "transform_reduce(): " << sum << endl;
}

transform_reduce的參數(shù):

  • 運行并行執(zhí)行的策略
  • 要處理的值范圍
  • 外層累積的初始值
  • 外層累積的操作
  • 在累積之前處理每個值的lambda表達式
2.5.2 transform_reduce()

使用transform_reduce()進行文件系統(tǒng)操作:

int main(int argc, char* argv[])
{if (argc < 2){cout << "Usage: " << argv[0] << " <path> \n";return EXIT_FAILURE;}namespace fs = filesystem;fs::path root{ argv[1] };// 初始化文件樹中所有文件路徑的列表vector<fs::path> paths;try{fs::recursive_directory_iterator dirpos{ root };copy(begin(dirpos), end(dirpos), back_inserter(paths));}catch (const exception& e){cerr << "EXCEPTION: " << e.what() << endl;return EXIT_FAILURE;}// 累積所有普通文件的大小auto sz = transform_reduce(execution::par,paths.cbegin(), paths.cend(),uintmax_t{ 0 },plus<>(),[](const fs::path& p){return is_regular_file(p) ? file_size(p) : uintmax_t{ 0 };});cout << "size of all " << paths.size()<< "regular files: " << sz << endl;
}

3. 新的STL算法詳解

3.1 for_each_n()

作為并行STL算法的一部分,原本的for_each_n又有了一個新的并行版本。類似于copy_n()fill_n()generate_n(),這個算法需要一個整數(shù)參數(shù)指出要對范圍內(nèi)多少個元素進行操作。

InputIterator
for_each_n (ExecutionPolicy&& pol,InputIterator beg,Size count,UnaryProc op);
  • 以beg為起點的前count個元素調(diào)用op。
  • 返回最后一個調(diào)用op元素的下一個位置。
  • 調(diào)用者必須保證有足夠多的元素。
  • op返回的任何值都會被忽略。
  • 如果沒有傳遞執(zhí)行策略,其他參數(shù)按順序傳遞即可。
  • 如果傳入了第一個可選的執(zhí)行策略參數(shù):
    • 對所有元素調(diào)用的op的順序沒有任何保證。
    • 調(diào)用者要保證并行操作不會產(chǎn)生數(shù)據(jù)競爭。
    • 迭代器必須至少是前向迭代器。

例如:

int main()
{vector<string> coll;for (int i = 0; i < 10000; ++i){coll.push_back(to_string(i));}// 修改前五個元素for_each_n(coll.begin(), 5,[](auto& elem){elem = "value " + elem;});for_each_n(coll.begin(), 10,[](const auto& elem){cout << elem << endl;});
}
3.2 新的STL數(shù)值算法

這些算法都定義在<numeric>中。

3.2.1 reduce()
typename iterator_traits<InputIterator>::value_type
reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg, InputIterator end);T 
reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg, InputIterator end,T initVal);T 
reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg, InputIterator end,T initVal,BinaryOp op);
3.2.2 transform_reduce()

變種一:

T
transform_reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg,InputIterator end,T initVal,BinaryOp op2,UnaryOp op1)
  • initVal op2 op1(a1) op2 op1(a2) op2 op1(a3) op2 ...

變種二:

T
transform_reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg1, InputIterator end1,InputIterator beg2,T initVal);T
transform_reduce (ExecutionPolicy&& pol, // 可選的InputIterator beg1, InputIterator end1,InputIterator beg2,T initVal,BinaryOp1 op1, BinaryOp2 op2);
  • 第一個形式計算范圍beg1和beg2開始的元素相乘再加上initVal。initVal += elem1 * elem2
  • 第二個形式是對beg1和beg2開始的元素調(diào)用op2,然后對initVal和上一步的結果調(diào)用op1。initVal = op1(initVal, op2(elem1, elem2))。
3.2.3 inclusive_scan()和exclusive_scan()
OutputIterator
inclusive_scan (ExcutionPolicy&& pol, // 可選的InputIterator inBeg, InputIterator inEnd,OutputIterator outBeg,BinaryOp op, // 可選的T initVal       // 可選的);OutputIterator
exclusive_scan (ExcutionPolicy&& pol, // 可選的InputIterator inBeg, InputIterator inEnd,OutputIterator outBeg,T initVal,      // 必須的BinaryOp op // 可選的);
  • 所有的形式是在計算范圍[inBeg, inEnd)內(nèi)每個元素和之前所有元素組合之后的值并寫入以outBeg開頭的目標范圍。
  • 對于值a1 a2 a3 ... aNinclusive_scan()計算initVal op a1, initVal op a1 op a2, initVal op a1 op a2 op a3, ...aN
  • 對于值a1 a2 a3 ... aNexclusive_scan()計算initVal, initVal op a1, initVal op a1 op a2, ... aN-1
  • 所有的形式都返回最后一個被寫入的位置的下一個位置。
  • 如果沒有傳遞op,會使用plus。
  • 如果沒有傳遞initVal,將不會添加初始值。第一個輸出的值將直接是第一個輸入的值。
  • op不能修改傳入的參數(shù)。
int main()
{array coll{ 3,1,7,0,4,1,6,3 };cout << " inclusive scan(): ";inclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "));cout << "\n exclusive_scan(): ";exclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),0);cout << "\n inclusive scan(): ";inclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),plus{},100);cout << "\n exclusive_scan(): ";exclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),100, plus{});
}

輸出結果:

 inclusive scan(): 3 4 11 11 15 16 22 25exclusive_scan(): 0 3 4 11 11 15 16 22inclusive scan(): 103 104 111 111 115 116 122 125exclusive_scan(): 100 103 104 111 111 115 116 122
3.2.4 transform_inclusive_scan()和transform_exclusive_scan()
OutputIterator
transform_inclusive_scan (ExcutionPolicy&& pol, // 可選的InputIterator inBeg, InputIterator inEnd,OutputIterator outBeg,BinaryOp op2, 			// 必須的UnaryOp op1, 		   // 必須的T initVal				   // 可選的);OutputIterator
transform_exclusive_scan (ExcutionPolicy&& pol, // 可選的InputIterator inBeg, InputIterator inEnd,OutputIterator outBeg,T initVal,				   // 必須的BinaryOp op2, 			// 必須的UnaryOp op1, 		   // 必須的			   );
  • 對于值a1 a2 a3 ... aNtransform_inclusive_scan計算initVal op2 op1(a1), initVal op2 op1(a1) op2 op1(a2), ... op2 op1(aN)。
  • 對于值a1 a2 a3 ... aNtransform_exclusive_scan計算initVal, initVal op2 op1(a1), initVal op2 op1(a1) op2 op1(a2), ... op2 op1(aN-1)
int main()
{array coll{ 3,1,7,0,4,1,6,3 };auto twice = [](int v) { return v * 2; };cout << " source:                       ";copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));cout << "\n transform_inclusive_scan():   ";transform_inclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),plus{}, twice);cout << "\n transform_inclusive_scan():   ";transform_inclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),plus{}, twice, 100);cout << "\n transform_exclusive_scan():   ";transform_exclusive_scan(coll.begin(), coll.end(),ostream_iterator<int>(cout, " "),100, plus{}, twice);
}

4. 子串和子序列搜索器

4.1 使用子串搜索器

新的搜索器主要是用來在長文本中搜索字符串(例如單詞或者短語)。因此首先演示一下在什么情況下使用它們,以及帶來的改變。

4.1.1 通過search()使用搜索器
  • 字符串成員函數(shù)find()

    size_t idx = text.find(sub);
    
  • 算法search()

    auto pos = std::search(text.begin(), text.end(), sub.begin(), sub.end());
    
  • 并行算法search()

    auto pos = std::search(execution::par, text.begin(), text.end(), sub.begin(), sub.end());
    
  • 使用default_searcher

    auto pos = search(text.begin(), text.end(), default_searcher{ sub.begin(),sub.end() });
    
  • 使用boyer_moore_searcher

    auto pos = search(text.begin(), text.end(), boyer_moore_searcher{ sub.begin(),sub.end() });
    
  • 使用boyer_moore_horspool_searcher

    auto pos = search(text.begin(), text.end(), boyer_moore_horspool_searcher{ sub.begin(),sub.end() });
    

Boyer-MooreBoyer-Moore-Horspool搜索器是非常著名的在搜索之前預計算“表”(存放哈希值)的算法,當搜索區(qū)間非常大時可以顯著加快搜索速度。算法需要隨機訪問迭代器。

搜索器的性能

  • 只使用非并行版本的search()通常是最慢的方法,因為對于text中的每個字符,我們都要查找以它開頭的子串是否匹配搜索目標。
  • 使用默認搜索器應該與上一周方法差不多,但是實際最差能比上一種慢三倍。
  • 使用find()可能會更快。這依賴于標準庫實現(xiàn)的質(zhì)量。
  • 如果文本或者要搜索的子串非常長,boyer_moore_searcher應該是最快的方法。和search()相比,甚至可能提供50倍到100倍左右的性能。
  • boyer_moore_horspool_searcher用時間換空間,雖然比boyer_moore_searcher慢,但占用的內(nèi)存會更少。
  • 使用并行search()的速度是普通的三倍,但遠遠小于新增的搜索器。
4.1.2 直接使用搜索器

另一個使用Boyer-Moore搜索器的方法是:你可以直接使用搜索器的函數(shù)調(diào)用運算符,會返回一個匹配子序列開頭和尾后迭代器的pair。

boyer_moore_searcher bmsearch{ sub.begin(),sub.end() };for (auto begend = bmsearch(text.begin(), text.end()); begend.first != text.end(); begend = bmsearch(begend.second, text.end()))
{cout << "found " << sub << " at index "<< begend.first - text.begin() << " - "<< begend.second - text.begin() << endl;
}
4.2 使用泛型子序列搜索器

原本這種算法使作為字符串搜索器開發(fā)的。然而,C++17將它們改進為泛型算法,因此,你可以在一個容器或者范圍內(nèi)搜索子序列。

int main()
{vector<int> coll;deque<int> sub{ 0,8,15,... };auto pos = search(coll.begin(), coll.end(), boyer_moore_searcher{ sub.begin(),sub.end() });// 或者下面:boyer_moore_searcher bm{ sub.begin(),sub.end() };auto [beg, end] = bm(coll.begin(), coll.end());if (beg != coll.end())cout << "found subsequence at " << beg - coll.begin() << endl;
}

想要能夠使用該算法,元素必須能用在哈希表中,也就是必須提供默認的哈希函數(shù)和==比較符。否則,使用搜索器謂詞。

4.3 搜索器謂詞

當使用搜索器時,你可以使用謂詞。出于兩個原因:

  • 你想自定義兩個元素的比較方式
  • 你想提供一個自定義的哈希函數(shù),也是Boyer-Moore搜索器必須的。

例如,這里用一個大小寫不敏感的搜索器來搜索子串:

boyer_moore_searcher bmic { sub.begin(), sub.end(),[](char c){return hash<char>{}(toupper(c));},[](char c1,char c2){return toupper(c1) == toupper(c2);}};

5. 其他工具函數(shù)和算法

5.1 size()/empty()/data()

C++新增加了三個輔助函數(shù):size()、empty()data()。都定義在<iterator>頭文件中。

5.1.1 泛型size()函數(shù)

該函數(shù)允許我們查任何范圍的大小,前提是由迭代器接口或者是原生數(shù)組。

template<typename T>
void printLast5(const T& coll)
{auto size{ size(coll) };cout << size << " elems: ";auto pos{ begin(coll) };// 將迭代器遞增到倒數(shù)第五個元素處if (size > 5){advance(pos, size - 5);cout << "...";}// 打印剩下的元素for (; pos != end(coll); ++pos){cout << *pos << " ";}cout << endl;
}
5.1.2 泛型empty()函數(shù)

類似size()empty()可以檢查容器、原生數(shù)組、initializer_list是否為空。

5.1.3 泛型data()函數(shù)

data()函數(shù)允許我們訪問集合的原始數(shù)據(jù)。

5.2 as_const()

新的輔助函數(shù)as_const()可以在不使用static_cast<>或者add_const_t<>類型特征的情況下把值轉換為響應的const類型。

vector<string> coll;foo(coll); 			  // 調(diào)用非常量版本
foo(as_const(coll)); // 調(diào)用常量版本
5.2.1 以常量引用捕獲

例如:

int main()
{vector<int> coll{ 8,5,7,42 };auto printColl = [&coll = as_const(coll)]{cout << "coll: ";for (int elem : coll){cout << elem << " ";}cout << endl;};
}
5.3 clamp()

C++17提供了一個新的工具函數(shù)clamp(),找出三個值大小居中的那個。

int main()
{for (int i : {-7, 0, 8, 15}){cout << clamp(i, 5, 13) << endl;}
}
5.4 sample()

C++17提供了sample()算法來從一個給定的范圍內(nèi)提取一個隨機的子集。有時候也被稱為水塘抽樣或者選擇抽樣。

#include <random>int main()
{vector<string> coll;for (int i = 0; i < 10000; ++i){coll.push_back("value" + to_string(i));}sample(coll.begin(), coll.end(),ostream_iterator<string>(cout, "\n"),10,default_random_engine{});
}

該函數(shù)有以下保證和約束:

  • 源范圍迭代器至少是輸入迭代器,目標迭代器至少是輸出迭代器。如果源迭代器表示輸入迭代器,那么目標迭代器必須是隨機訪問迭代器。
  • 如果目標區(qū)間大小不夠有沒有使用插入迭代器,那么寫入目標迭代器可能會導致未定義行為。
  • 算法返回最后一個被拷貝元素的下一個位置。
  • 目標迭代器指向的區(qū)間不能在源區(qū)間中。
  • num可能是整數(shù)類型。如果源區(qū)間的元素數(shù)量不足,將會提取源區(qū)間的所有元素。
  • 只要源區(qū)間的迭代器不只是輸入迭代器,那么提取的子集中的順序保持穩(wěn)定。
int main()
{vector<string> coll;for (int i = 0; i < 10000; ++i){coll.push_back("value" + to_string(i));}// 用一個隨機數(shù)種子初始化Mersenne Twister引擎:random_device rd;mt19937 eng{ rd() };vector<string> subset;subset.resize(100);auto end = sample(coll.begin(), coll.end(),subset.begin(),10,eng);for_each(subset.begin(), end, [](const auto& s){cout << "random elem:" << s << endl;});
}

6. 容器和字符串擴展

6.1 節(jié)點句柄

C++17引入把某個節(jié)點從關聯(lián)或無需容器中移除或移入的功能。

6.1.1 修改key
int main()
{map<int, string> m{ {1,"mango"},{2,"papaya"},{3,"guava"} };auto nh = m.extract(2); // nh的類型為decltype(m)::node_typenh.key() = 4;m.insert(move(nh));for (const auto& [key, value] : m){cout << key << " : " << value << endl;}
}

這段代碼是把key為2的的元素結點移除了容器,然后修改了key,最后有移進了容器。C++17之前,如果想修改一個key,必須刪除舊結點然后再插入一個value相同的新節(jié)點。如果我們使用節(jié)點句柄,將不會發(fā)送內(nèi)存分配。

6.1.2 在容器之間移動節(jié)點句柄

你也可以使用節(jié)點句柄把一個元素從一個容器move到另一個容器。

template<typename T1,typename T2>
void print(const T1& coll1, const T2& coll2)
{cout << "values:\n";for (const auto& [key, value] : coll1){cout << " [" << key << " : " << value << "]";}cout << endl;for (const auto& [key, value] : coll2){cout << " [" << key << " : " << value << "]";}cout << endl;
}int main()
{multimap<double, string> src{ {1.1,"one"},{2.2,"two"},{3.3,"three"} };map<double, string> dst{ {3.3,"old data"} };print(src, dst);dst.insert(src.extract(src.find(1.1)));dst.insert(src.extract(2.2));print(src, dst);
}
6.1.3 合并容器

以節(jié)點句柄API為基礎,現(xiàn)在所有的關聯(lián)和無需容器都提供了成員函數(shù)merge(),可以把一個容器中的所有元素合并到另一個容器中。如果源容器中的某個元素和目標容器的元素的key值相同,那么它仍然保留在源容器中。

template<typename T1,typename T2>
void print(const T1& coll1, const T2& coll2)
{cout << "values:\n";for (const auto& [key, value] : coll1){cout << " [" << key << " : " << value << "]";}cout << endl;for (const auto& [key, value] : coll2){cout << " [" << key << " : " << value << "]";}cout << endl;
}int main()
{multimap<double, string> src{ {1.1,"one"},{2.2,"two"},{3.3,"three"} };map<double, string> dst{ {3.3,"old data"} };print(src, dst);// 把src的所有元素和并到dst中dst.merge(src);print(src, dst);
}
6.2 emplace改進
6.2.1 emplace函數(shù)的返回類型

對于順序容器vector<>deque<>、list<>、forward_list<>,還有容器適配器stack<>queue<>。他們的emplace函數(shù)現(xiàn)在返回新插入的對象的引用。例如:

foo(myVector.emplace_back(...));
// 等同于
myVector.emplace_back(...);
foo(myVector.back());
6.2.2 map的try_emplace()和insert_or_assign()
  • try_emplace()用移動語義構造了一個新的值。
  • insert_or_assign()稍微改進了插入/更新元素的方法。
6.2.3 try_emplace()

考慮如下代碼:

map<int,string> m;
m[42] = "hello";
string s{"world"};
m.emplace(42,move(s)); // 可能移動,但42已經(jīng)存在了可能不會移動

這樣調(diào)用之后s是否保持原本的值是未定義的。同樣使用insert()之后也可能是這樣。

m.insert({42,move(s))});

新的成員函數(shù)try_emplace()保證在沒有已經(jīng)存在元素時才會move走傳入的值:

m.try_emplace(42,move(s)); // 如果插入失敗不會move
6.2.4 insert_or_assign()

另外,新的成員函數(shù)insert_or_assign()保證把值移動道一個新的元素或者已經(jīng)存在的元素中。

m.insert_or_assgin(42,move(s)); // 總是會move
6.3 對不完全類型的容器支持

自從C++17起,vector、list、forward_list被要求支持不完全類型。

你現(xiàn)在可以定義一個類型,內(nèi)部遞歸的包含一個自身類型的容器。例如:

struct Node
{string value;vector<Node> children;
};
6.4 string的改進
  • 對于非常量string(),你現(xiàn)在可以調(diào)用data()吧底層的字符序列當做原生C字符串來訪問。
auto cstr = mystring.data();
cstr[6] = 'w'; // OKchar *cstr = mystring.data(); // OK

7. 多線程和并發(fā)

7.1 補充的互斥量和鎖
7.1.1 scoped_lock

C++11引入了一個簡單的lock_guard來實現(xiàn)RAII風格的互斥量上鎖:

  • 構造函數(shù)上鎖
  • 析構函數(shù)解鎖

不幸的是,沒有標準化的可變參數(shù)模板可以用來在一條語句中同時鎖住多個互斥量。

scoped_lock解決了這個問題。它允許我們同時鎖住一個或多個互斥量,互斥量的類型可以不同。

int main()
{vector<string> alllssues;mutex alllssuesMx;vector<string> openlssues;timed_mutex openlssuesMx;// 同時鎖住兩個issue列表{scoped_lock lg(alllssuesMx, openlssuesMx);// .. 操作}
}

類似于一下C++11代碼:

// 同時鎖住兩個issue列表
{lock(alllssuesMx, openlssuesMx); // 避免死鎖的方式上鎖lock_guard<mutex> lg1(alllssuesMx, adopt_lock);lock_guard<timed_mutex> lg2(openlssuesMx, adopt_lock);// .. 操作
}

因此,當傳入的互斥量超過一個時,scoped_lock的構造函數(shù)會使用可變參數(shù)的快捷函數(shù)lock(),這個函數(shù)會保證不會導致死鎖。

注意你也可以傳遞已經(jīng)被鎖住的互斥量

// 同時鎖住兩個issue列表
{lock(alllssuesMx, openlssuesMx); // 避免死鎖的方式上鎖scoped_lock lg{adpot_lock, alllssuesMx, openlssuesMx};// .. 操作
}
7.1.2 shared_mutex

C++14添加了一個shared_timed_mutex來支持讀/寫鎖,它支持多個線程同時讀一個值,偶爾會有一個線程更改值?,F(xiàn)在引入了shared_mutex,定義在頭文件<shared_mutex>

支持以下操作:

  • 對于獨占鎖:lock()、try_lock()、unlock()
  • 對于共享的讀訪問:lock_shared()、try_lock_shared()、unlock_shared()
  • native_handle()

假設你有一個共享的vector,被多個線程讀取,偶爾會被修改:

vector<double> v; // 共享的資源
shared_mutex vMutex;int main()
{if (shared_lock sl(vMutex); v.size() > 0){// 共享讀權限}{scoped_lock sl(vMutex);// 獨占寫權限}
}
7.2 原子類型的is_always_lock_free

你現(xiàn)在可以使用一個C++庫的特性來檢查一個特定的原子類型是否總是可以在無鎖的情況下使用。例如:

if constexpr(atomic<int>::is_always_lock_free)
{// ...
}
else 
{// ...
}

如果一個原子類型的is_always_lock_free返回true,那么該類型的對象is_lock_free()成員也一定會返回true:

if constexpr(atomic<T>::is_always_lock_free) 
{assert(atomicT>{}.is_lock_free()); // 絕不會失敗
}

在C++17之前,只能使用相應的宏來判斷,例如當ATOMIC_INT_LOCK_FREE返回2的時候相當于is_always_lock_free返回true。

7.3 cache行大小

程序有時候需要處理cache行大小的能力有以下兩種:

  1. 不同線程訪問的不同對象不屬于同一個cache是很重要的。否則,不同線程并行訪問對象時cache行緩存的內(nèi)存可能需要同步。
  2. 你可能會想把多個對象放在同一個cache行中,這樣訪問了第一個對象之后,訪問接下來的對象就可以直接在cache行中訪問。

C++標準庫在頭文件中引入了兩個內(nèi)聯(lián)變量:

namespace std
{inline constexpr size_t hardware_destructive_interference_size; // 可能被不同線程并發(fā)訪問的兩個對象之間的最小偏移量inline constexpr size_t hardware_constructive_interference_size; // 兩個想被放在同一個L1緩存行的對象合起來的最大大小
}

如果你想要在不同的線程里訪問兩個不同(原子)的對象:

struct Data
{alignas(std::hardware_destructive_interference_size) int valueForThreadA;alignas(std::hardware_destructive_interference_size) int valueForThreadB;
};

如果你想要在同一個線程里訪問不同的(原子)對象

struct Data {int valueForThraedA;int otherValueForTheThreadA;
};

8. 標準庫中其他微小的修改和特性

8.1 std::uncaught_exceptions()

C++中存在一個模式RAII,這是一種安全處理那些你必須要釋放或清理的資源的方式。在構造一個對象的時候將所需要的資源分配給它,在析構中將分配的資源進行釋放。

然而,有的時候資源的“釋放操作”依賴于我們到底是正常執(zhí)行離開了作用域還是因為異常離開了作用域。一個例子是事務性資源,如果我們正常執(zhí)行離開了作用域,我們可能想進行提交操作,而當因為異常離開作用域時想進行回滾操作。為了達到這個目的,C++11引入了std::uncaught_expection(),用法如下:

class Request
{
public:~Request(){if(std::uncaught_expection()) rollback(); // 如果沒有異常情況會調(diào)用rollback()else commit();}
};

然而,在如下場景中使用這個API不能正常工作,當我們正在處理異常時,如果創(chuàng)建了新的Request對象,那么即使在使用它的期間沒有異常拋出,它的析構函數(shù)總是會調(diào)用rollback()。

try
{...
}
catch(...) 
{Request r2{...};  
}

C++17解決了這個問題,對Request類進行以下修改:

class Request
{
private:int initialUncaught{std::uncaught_expections()};
public:~Request(){if(std::uncaught_expections() > initialUncaught) rollback(); // 如果沒有異常情況會調(diào)用rollback()else commit();}
};

舊的不帶s的API自C++17起被廢棄,不應該再被使用。

8.2 共享指針的改進

C++17添加了一些共享指針的改進,且成員函數(shù)unique()已經(jīng)被廢棄了。

8.2.1 對原生C數(shù)組的共享指針的特殊處理

自從C++17起可以對其使用特定的deleter函數(shù),C++11unique_ptr已經(jīng)可以做到了,例如:

std::shared_ptr<std::string> p{new std::string[10], [](std::string* p){delete[] p;
}};

當實例化是數(shù)組時,不再使用operator*,而是使用operator[]:

std::shared_ptr<std::string> ps{new std::string};
*ps = "hello"; // OK
ps[0] = "hello"; // ERRORstd::shared_ptr<std::string[]> parr{new std::string[10]};
*parr = "hello"; // ERROR
parr[0] = "hello"; // OK
8.2.2 共享指針的reinterpret_pointer_cast

除了static_pointer_cast、dynamic_pointer_castconst_pointer_cast之外,可以調(diào)用reinterpret_pointer_cast。

8.2.3 共享指針的weak_type

為了支持在泛型代碼中使用弱指針,共享指針提供了一個新的成員weak_type。例如:

template<typename T>
void ovserve(T sp)
{typename T::weak_type wp{sp};
}
8.2.4 共享指針的weak_from_this

C++17起,有一個額外的輔助函數(shù)可以返回一個指向對象的弱指針:

Person *pp = new Person{};
std::shared_ptr<Person> sp{pp};std::weak_ptr<Person> wp{pp->weak_from_this()}; // wp分享了sp擁有的所有權
8.3 數(shù)學拓展

C++17引入了以下的數(shù)學函數(shù)。

8.3.1 最大公約數(shù)和最小公倍數(shù)

在頭文件<numeric>中:

  • gcd(x, y) 返回x和y的最大公約數(shù)
  • lcm(x, y) 返回x和y的最小公倍數(shù)
8.3.2 std::hypot()的三參數(shù)重載

在頭文件<cmath>中:

  • hypot(x, y, z) 返回三個參數(shù)的平方之和的平方根
8.3.3 數(shù)學中的特殊函數(shù)
名稱含義
assoc_laguerre()關聯(lián)Laguerre多項式
assoc_legendre()關聯(lián)Legendre函數(shù)
beta()beta函數(shù)
comp_ellint_1()第一類完整橢圓積分
comp_ellint_2()第二類完整橢圓積分
comp_elint_3()第三類完整橢圓積分
cyl_bessel_i()規(guī)則圓柱貝塞爾函數(shù)
cyl_bessel_j()第一類圓柱貝塞爾函數(shù)
cyl_bessel_k()不規(guī)則圓柱貝塞爾函數(shù)變體
cyl_neumann()圓柱諾依曼函數(shù)
ellint_1()第一類不完整橢圓積分
elint_2()第二類不完整橢圓積分
elint_3()第三類不完整橢圓積分
expint()指數(shù)積分
hermite()Hermite多項式
laguerre()Laguerre多項式
legendre()Legendre多項式
riemann_zeta()黎曼zeta函數(shù)
sph_bessel()第一類球形貝塞爾函數(shù)
sph_legendre()關聯(lián)球形Legendre函數(shù)
sph_neumann()球形諾依曼函數(shù)
8.3.4 chrono拓展

對于時間段和時間點添加了新的舍入函數(shù):

  • round(): 舍入到最近的整數(shù)值
  • floor(): 向負無窮舍入到最近的整數(shù)值(向下取整)
  • ceil(): 向正無窮舍入到最近的整數(shù)值(向上取整)
8.3.5 constexpr拓展和修正

最重要的修正有:

  • 對于std::array,下面的函數(shù)是constexpr:
    • begin()、end()、cbegin()、cend()、rbegin()、rend()、crbegin()、crend()
    • 非常量數(shù)組的operator[]、at()、front()、back()
    • data()
  • 范圍訪問的泛型獨立函數(shù)和輔助函數(shù)。
  • 類std::reverse_iterator和std::move_iterator的所有操作
  • C++標準庫整個時間庫的部分。
  • 所有的std::char_traits特化的成員函數(shù)。
8.3.6 noexpect拓展和修正

最重要的修正有:

  • std::vector<>和std::string,C++17保證下列操作不會拋出異常
    • 默認構造函數(shù)
    • 移動構造函數(shù)
    • 以分配器為參數(shù)的構造函數(shù)
  • 對于所有的容器,下列操作不會拋出異常:
    • 移動賦值運算符
    • swap函數(shù)
http://www.risenshineclean.com/news/26906.html

相關文章:

  • 北京制作頁面網(wǎng)站搜索優(yōu)化官網(wǎng)
  • 微信朋友圈廣告投放平臺杭州上城區(qū)抖音seo有多好
  • 找美工做網(wǎng)站多少錢長沙seo優(yōu)化推廣公司
  • 洛陽做網(wǎng)站哪家便宜沈陽seo排名收費
  • 靜態(tài)網(wǎng)站制作模板百度seo關鍵詞排名優(yōu)化
  • 創(chuàng)業(yè)商機網(wǎng)餐飲seoapp推廣
  • dz論壇怎么做視頻網(wǎng)站上海十大營銷策劃公司
  • 日照網(wǎng)站建設哪家好看廣告賺錢的平臺
  • 怎么用css做網(wǎng)站背景圖整站優(yōu)化seo公司哪家好
  • 大連網(wǎng)站建設特色南京seo關鍵詞排名
  • asp動態(tài)網(wǎng)站建設模擬搜索點擊軟件
  • 源碼下載網(wǎng)站源碼廣西網(wǎng)絡優(yōu)化seo
  • 網(wǎng)站下載的軟件怎么安裝代寫1000字多少錢
  • 集團網(wǎng)站建設要多少錢sem推廣軟件選哪家
  • 一級a做爰片免費觀網(wǎng)站看無碼滄州網(wǎng)站建設
  • 網(wǎng)站建設英語翻譯資料產(chǎn)品軟文范例軟文
  • 深圳做網(wǎng)站 漢獅網(wǎng)絡seo合作代理
  • 長沙網(wǎng)站策劃在線優(yōu)化網(wǎng)站
  • 鄂州市政府網(wǎng)長沙seo培訓
  • 青島學網(wǎng)站建設的大學搜索關鍵詞技巧
  • 做網(wǎng)站需要公司么中國制造網(wǎng)網(wǎng)站類型
  • 做dhl底單的網(wǎng)站是 什么網(wǎng)絡營銷與直播電商專業(yè)就業(yè)前景
  • 致遠oa協(xié)同管理系統(tǒng)優(yōu)化大師apk
  • 瑞安外貿(mào)網(wǎng)站制作網(wǎng)站管理系統(tǒng)
  • 帝國+只做網(wǎng)站地圖百度app怎么找人工客服
  • 網(wǎng)站開發(fā) 后端服務草根seo視頻大全
  • 做模型網(wǎng)站賺錢么高端網(wǎng)站建設制作
  • 廣東全網(wǎng)推廣手機流暢優(yōu)化軟件
  • 謝崗鎮(zhèn)仿做網(wǎng)站百度免費
  • 美女網(wǎng)站源碼策劃公司是做什么的