国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C/C++ - C++ vector擴(kuò)容解析noexcept應(yīng)用場景

C++ vector擴(kuò)容解析noexcept應(yīng)用場景

2021-09-28 10:44張雅宸 C/C++

這篇文章主要介紹了C++ vector擴(kuò)容解析noexcept應(yīng)用場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

c++11提供了關(guān)鍵字noexcept,用來指明某個函數(shù)無法――或不打算――拋出異常:

void foo() noexcept; // a function specified as will never throw
void foo2() noexcept(true); // same as foo
void bar(); // a function might throw exception
void bar2() noexcept(false); // same as bar

所以我們需要了解以下兩點:

noexcept有什么優(yōu)點,例如性能、可讀性等等。

需不需要在代碼中大量使用noexcept。

noexcept優(yōu)點

我們先從std::vector入手來看一下第一點。

我們知道,vector有自己的capacity,當(dāng)我們調(diào)用push_back但是vector容量滿時,vector會申請一片更大的空間給新容器,將容器內(nèi)原有的元素copy到新容器內(nèi):

C++ vector擴(kuò)容解析noexcept應(yīng)用場景

但是如果在擴(kuò)容元素時出現(xiàn)異常怎么辦?

申請新空間時出現(xiàn)異常:舊vector還是保持原有狀態(tài),拋出的異常交由用戶自己處理。

copy元素時出現(xiàn)異常:所有已經(jīng)被copy的元素利用元素的析構(gòu)函數(shù)釋放,已經(jīng)分配的空間釋放掉,拋出的異常交由用戶自己處理。

這種擴(kuò)容方式比較完美,有異常時也會保持上游調(diào)用push_back時原有的狀態(tài)。

但是為什么說比較完美,因為這里擴(kuò)容還是copy的,當(dāng)vector內(nèi)是一個類且持有資源較多時,這會很耗時。所以c++11推出了一個新特性:move,它會將資源從舊元素中“偷”給新元素(對move不熟悉的同學(xué)可以自己查下資料,這里不展開說了)。應(yīng)用到vector擴(kuò)容的場景中:當(dāng)vector中的元素的移動拷貝構(gòu)造函數(shù)是noexcept時,vector就不會使用copy方式,而是使用move方式將舊容器的元素放到新容器中:

C++ vector擴(kuò)容解析noexcept應(yīng)用場景

利用move的交換類資源所有權(quán)的特性,使用vector擴(kuò)容效率大大提高,但是當(dāng)發(fā)生異常時怎么辦:
原有容器的狀態(tài)已經(jīng)被破壞,有部分元素的資源已經(jīng)被偷走。若要恢復(fù)會極大增加代碼的復(fù)雜性和不可預(yù)測性。所以只有當(dāng)vector中元素的move constructor是noexcept時,vector擴(kuò)容才會采取move方式來提高性能。

剛才總結(jié)了利用noexcept如何提高vector擴(kuò)容。實際上,noexcept還大量應(yīng)用在swap函數(shù)和move assignment中,原理都是一樣的。

noexcept使用場景

上面提到了noexcept可以使用的場景:

  • move constructor
  • move assignment
  • swap

很多人的第一念頭可能是:我的函數(shù)現(xiàn)在看起來明顯不會拋異常,又說聲明noexcept編譯器可以生成更高效的代碼,那能加就加唄。但是事實是這樣嗎?

這個問題想要討論清楚,我們首先需要知道以下幾點:

函數(shù)自己不拋異常,但是不代表它們內(nèi)部的調(diào)用不會拋出異常,并且編譯器不會提供調(diào)用者與被調(diào)用者的noexcept一致性檢查,例如下述代碼是合法的:

void g(){
  ...    //some code
}
void f() noexcept
{
  … 			//some code
  g();
}

當(dāng)一個聲明為noexcept的函數(shù)拋出異常時,程序會被終止并調(diào)用std::terminate();

所以在我們的代碼內(nèi)部調(diào)用復(fù)雜,鏈路較長,且隨時有可能加入新feature時,過早給函數(shù)加上noexcept可能不是一個好的選擇,因為noexcept一旦加上,后續(xù)再去掉也會變得困難 : 調(diào)用方有可能看到你的函數(shù)聲明為noexcept,調(diào)用方也會聲明為noexcept。但是當(dāng)你把函數(shù)的noexcept去掉卻沒有修改調(diào)用方的代碼時,當(dāng)異常拋出到調(diào)用方會導(dǎo)致程序終止。

目前主流的觀點是:

加noexcept

函數(shù)在c++98版本中已經(jīng)被聲明為throw()

上文提到過的三種情況:move constructor、move assignmemt、swap。如果這些實現(xiàn)不拋出異常,一定要使用noexcept。
leaf function. 例如獲取類成員變量,類成員變量的簡單運算等。下面是stl的正向iterator中的幾個成員函數(shù):

# if __cplusplus >= 201103L
# define _GLIBCXX_NOEXCEPT noexcept
# else
# define _GLIBCXX_NOEXCEPT

 reference
   operator*() const _GLIBCXX_NOEXCEPT
   { return *_M_current; }

   pointer
   operator->() const _GLIBCXX_NOEXCEPT
   { return _M_current; }

   __normal_iterator&
   operator++() _GLIBCXX_NOEXCEPT
   {
	++_M_current;
	return *this;
   }

   __normal_iterator
   operator++(int) _GLIBCXX_NOEXCEPT
   { return __normal_iterator(_M_current++); }

不加noexcept

除了上面的要加的情況,其余的函數(shù)不要加noexcept就可以。

最后我們看一下vector如何實現(xiàn)利用noexcept move constructor擴(kuò)容以及move constructor是否聲明noexcept對擴(kuò)容的性能影響。

如何實現(xiàn)利用noexcept move constructor擴(kuò)容

這里就不貼大段的代碼了,每個平臺的實現(xiàn)可能都不一樣,我們只關(guān)注vector是怎么判斷調(diào)用copy constructor還是move constructor的。

其中利用到的核心技術(shù)有:

  • type trait
  • iterator trait
  • move iterator
  • std::forward

核心代碼:

template <typename _Iterator, typename _ReturnType = typename conditional<
                 __move_if_noexcept_cond<typename iterator_traits<_Iterator>::value_type>::value,
                 _Iterator, move_iterator<_Iterator>>::type>
inline _GLIBCXX17_CONSTEXPR _ReturnType __make_move_if_noexcept_iterator(_Iterator __i) {
 return _ReturnType(__i);
}

template <typename _Tp>
struct __move_if_noexcept_cond
  : public __and_<__not_<is_nothrow_move_constructible<_Tp>>, is_copy_constructible<_Tp>>::type {};

這里用type trait和iterator trait聯(lián)合判斷:假如元素有noexcept move constructor,那么is_nothrow_move_constructible=1 => __move_if_noexcept_cond=0 => __make_move_if_noexcept_iterator返回一個move iterator。這里move iterator迭代器適配器也是一個c++11新特性,用來將任何對底層元素的處理轉(zhuǎn)換為一個move操作,例如:

std::list<std::string> s;
std::vector<string> v(make_move_iterator(s.begin()),make_move_iterator(s.end())); //make_move_iterator返回一個std::move_iterator

然后上游利用生成的move iterator進(jìn)行循環(huán)元素move:

{
 for (; __first != __last; ++__first, (void)++__cur) std::_Construct(std::__addressof(*__cur), *__first);
 return __cur;
}

template <typename _T1, typename... _Args>
inline void _Construct(_T1 *__p, _Args &&... __args) {
 ::new (static_cast<void *>(__p)) _T1(std::forward<_Args>(__args)...);   //實際copy(或者move)元素
}

其中_Construct就是實際copy(或者move)元素的函數(shù)。這里很關(guān)鍵的一點是:對move iterator進(jìn)行解引用操作,返回的是一個右值引用。,這也就保證了,當(dāng)__first類型是move iterator時,用_T1(std::forward<_Args>(__args)...進(jìn)行“完美轉(zhuǎn)發(fā)”才調(diào)用_T1類型的move constructor,生成的新對象被放到新vector的__p地址中。

總結(jié)一下過程就是:

利用type trait和iterator trait生成指向舊容器的normal iterator或者move iterator

循環(huán)將舊容器的元素搬到新容器。如果指向舊容器的是move iterator,那么解引用會返回右值引用,會調(diào)用元素的move constructor,否則調(diào)用copy constructor。

大家可以用下面這段簡單的代碼在自己的平臺打斷點調(diào)試一下:

class A {
 public:
 A() { std::cout << "constructor" << std::endl; }
 A(const A &a) { std::cout << "copy constructor" << std::endl; }
 A(const A &&a) noexcept { std::cout << "move constructor" << std::endl; }
};

int main() {
 std::vector<A> v;
 for (int i = 0; i < 10; i++) {
  A a;
  v.push_back(a);
 }

 return 0;
}

noexcept move constructor對性能的影響

這篇文章C++ NOEXCEPT AND MOVE CONSTRUCTORS EFFECT ON PERFORMANCE IN STL CONTAINERS介紹了noexcept move constructor對耗時以及內(nèi)存的影響,這里不重復(fù)贅述了,感興趣的可以自己試一下。

C++ vector擴(kuò)容解析noexcept應(yīng)用場景

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://www.cnblogs.com/zhangyachen/p/13625683.html

延伸 · 閱讀

精彩推薦
  • C/C++深入理解goto語句的替代實現(xiàn)方式分析

    深入理解goto語句的替代實現(xiàn)方式分析

    本篇文章是對goto語句的替代實現(xiàn)方式進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下...

    C語言教程網(wǎng)7342020-12-03
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內(nèi)存中的數(shù)據(jù)都是暫時的,當(dāng)程序結(jié)束時,它們都將丟失,為了永久性的保存大量的數(shù)據(jù),C語言提供了對文件的操作,這篇文章主要給大家介紹了關(guān)于C語言中文件...

    針眼_6702022-01-24
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++學(xué)習(xí)C++編程的必備軟件

    學(xué)習(xí)C++編程的必備軟件

    本文給大家分享的是作者在學(xué)習(xí)使用C++進(jìn)行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言實現(xiàn)電腦關(guān)機(jī)程序

    C語言實現(xiàn)電腦關(guān)機(jī)程序

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)電腦關(guān)機(jī)程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++c++ 單線程實現(xiàn)同時監(jiān)聽多個端口

    c++ 單線程實現(xiàn)同時監(jiān)聽多個端口

    這篇文章主要介紹了c++ 單線程實現(xiàn)同時監(jiān)聽多個端口的方法,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數(shù)使用

    詳解c語言中的 strcpy和strncpy字符串函數(shù)使用

    strcpy 和strcnpy函數(shù)是字符串復(fù)制函數(shù)。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數(shù)使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C/C++經(jīng)典實例之模擬計算器示例代碼

    C/C++經(jīng)典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關(guān)于C/C++經(jīng)典實例之模擬計算器的相關(guān)資料,文中通過示...

    jia150610152021-06-07
主站蜘蛛池模板: 日韩精品一区二区三区在线观看 | 日韩成人在线影院 | 免费一级在线视频 | 玖玖国产精品视频 | 日日干天天干 | 国产精品久久国产精品 | 一久久久 | 激情视频在线观看 | 在线观看 亚洲 | 亚洲一区视频 | 日韩 欧美 中文 | 欧美一级在线 | 天天干天天看天天操 | 国产一区久久 | 欧美视频一区二区 | www.国产一区 | 日日搞夜夜操 | 亚洲午夜精品视频 | 久久久中文 | 91av精品视频 | 亚洲不卡 | 91av在线电影 | 一区二区在线视频 | 成人精品国产免费网站 | 久草电影在线 | 欧美激情精品久久久久久 | 国产一区二区三区久久 | 91精品国产综合久久婷婷香蕉 | 国产资源在线看 | 黄色成人在线 | 北条麻妃一区二区三区中文字幕 | 精品影院| 亚洲精品视频免费观看 | 亚洲欧美自拍视频 | 欧美精品一二区 | 蜜桃一区 | 激情一区二区 | 午夜视频在线 | 欧美一级在线观看 | 一区二区三区四区视频 | 欧美日韩精品在线 |