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

當(dāng)前位置: 首頁 > news >正文

制作網(wǎng)站參考案例廣州優(yōu)化疫情防控舉措

制作網(wǎng)站參考案例,廣州優(yōu)化疫情防控舉措,用asp.net做后臺(tái)網(wǎng)站,網(wǎng)站建設(shè) 內(nèi)容缺乏0.前情提要 (很久)之前上編譯原理時(shí),一次實(shí)驗(yàn)課需要補(bǔ)充完善一個(gè)用 c 寫的詞法分析器;而這個(gè)分析器在定義語法樹結(jié)點(diǎn)時(shí)使用了 union 存儲(chǔ)語言中不同表達(dá)式的類型標(biāo)簽或值本身。因?yàn)楫?dāng)時(shí)剛好學(xué)完了 cpp,拿著錘子看啥都…

0.前情提要

(很久)之前上編譯原理時(shí),一次實(shí)驗(yàn)課需要補(bǔ)充完善一個(gè)用 c 寫的詞法分析器;而這個(gè)分析器在定義語法樹結(jié)點(diǎn)時(shí)使用了 union 存儲(chǔ)語言中不同表達(dá)式的類型標(biāo)簽或值本身。因?yàn)楫?dāng)時(shí)剛好學(xué)完了 cpp,拿著錘子看啥都像釘子,所以嘗試(并且勉強(qiáng)成功地)將給好的程序用 cpp 重寫了一遍(好孩子不要學(xué))。

重寫過程中遇到的最大問題就是:源程序中的 union 與 cpp 的類型系統(tǒng)不太兼容,不管怎么寫編譯器都會(huì)給我糊一個(gè)編譯錯(cuò)誤;這就引出了一個(gè)問題:cpp 的 union 究竟該如何使用。

1.union 與 cpp

從類型論角度來看,union 是一種“和類型1”,這種類型允許在同一個(gè)地址空間、但在不同時(shí)間存放不同類型的數(shù)據(jù)。

#include <bitset>
#include <iostream>// 例如說對(duì)于下面這個(gè) union
union U {float mem1;int mem2;
};int main()
{static_assert(sizeof(U) == std::max(sizeof(float), sizeof(int)));// union 的大小通常等于其最大的成員分量的大小U tmp { 3.14f }; // 可以先存入一個(gè) float 類型數(shù)據(jù)std::cout << tmp.mem1 << std::endl; // 使用掉它tmp.mem2 = 114514; // 稍后再往同一個(gè)內(nèi)存空間存另一種類型的數(shù)據(jù)std::cout << tmp.mem1 << std::endl;// 這樣就實(shí)現(xiàn)了一段內(nèi)存空間的復(fù)用
}

union 類型經(jīng)常被用在一些語法解析器中,因?yàn)樗闷饋韺?shí)在是很方便(指能夠以定長(zhǎng)空間存儲(chǔ)多種類型數(shù)據(jù))。

自 cpp11 后,cpp 標(biāo)準(zhǔn)提高了類型安全的要求,但如果我們看一下 union 定義就會(huì)發(fā)現(xiàn),這個(gè)語言功能天生就極其的類型不安全。舉個(gè)例子,下面這段代碼就直接“擊穿”了 cpp 的類型系統(tǒng)(雖然這種擊穿隨處可見):

#include <iostream>
#include <cstring>union Breaker {int answer;double magic_number;char* magic_string;
};int main()
{// 活躍成員為 int 類型// 活躍成員是指最近一次存有有效數(shù)據(jù)的成員分量Breaker bk { 42 };std::cout << bk.answer << std::endl; // Okstd::cout << bk.magic_number << std::endl; // 能夠通過編譯,但運(yùn)行期行為未定義// std::cout << strlen( bk.magic_string ) << std::endl; // 同上,但這樣做通常會(huì)導(dǎo)致越界訪問,進(jìn)而導(dǎo)致程序 crashbk.magic_string = new char[21] { "Say something" };std::cout << bk.magic_string << std::endl;bk.magic_number = 3.14; // 活躍成員的切換導(dǎo)致指向堆上資源的指針被覆蓋// 最終導(dǎo)致內(nèi)存泄漏發(fā)生
}

得益于 cpp “充分信任程序員2”的理念,除非編譯器對(duì)這種行為有單獨(dú)且明確的警告,否則這種代碼完全能夠通過編譯并執(zhí)行(cpp 是自由的);但這種非主觀地突破類型系統(tǒng)的行為通常會(huì)導(dǎo)致程序出現(xiàn)各種運(yùn)行期錯(cuò)誤,最明顯不過的就是上述代碼的越界訪問。

并且,如果試圖往 union 中填入標(biāo)準(zhǔn)庫的容器類型或是其他自定義的對(duì)象類型(這相當(dāng)實(shí)用且常見),編譯器有時(shí)還會(huì)沒頭沒尾地爆出“默認(rèn)析構(gòu)函數(shù)已被棄置”的編譯錯(cuò)誤;這是為什么?

2.讓代碼先通過編譯

答案是標(biāo)準(zhǔn)的規(guī)定。根據(jù) cpp 標(biāo)準(zhǔn):

  1. 在 cpp11 以前,帶有非平凡的構(gòu)造函數(shù)和析構(gòu)函數(shù)的非靜態(tài)成員(下稱非平凡成員)不能被放置在 union 中;
  2. 在 cpp11 之后,非平凡成員可以被填入 union 中,但這個(gè) union 自己的復(fù)制、移動(dòng)、默認(rèn)構(gòu)造函數(shù)以及復(fù)制賦值、移動(dòng)賦值運(yùn)算符和析構(gòu)函數(shù)都不會(huì)被編譯器默認(rèn)提供,并且由用戶提供的默認(rèn)構(gòu)造函數(shù)中只允許一個(gè)成員使用默認(rèn)成員初始化器(就是構(gòu)造函數(shù)里的那個(gè)冒號(hào))。

這都 4202 年了,cpp11 之前的事情我們不管,現(xiàn)在只需要把焦點(diǎn)聚焦在 cpp11 后的標(biāo)準(zhǔn)規(guī)定上。那么首先,什么是“非平凡”?

平凡類型指的是標(biāo)量類型(如 intstd::nullptr_t 等)和平凡類類型,以及前兩種類型組成的數(shù)組類型。

平凡類類型必須滿足:

  1. 它是一個(gè)可平凡復(fù)制類(也就是可以被以 memcpy 這種方式復(fù)制);
  2. 有一個(gè)以上的合格的平凡默認(rèn)構(gòu)造函數(shù),并且這些構(gòu)造函數(shù)必須什么都不干(即由編譯器提供)。

這里的定義很復(fù)雜(一般也懶得看),要求也很苛刻,但不滿足約束條件的結(jié)果只有一個(gè):該 union 的六大特殊成員函數(shù)3都會(huì)被默認(rèn)棄置(即編譯器不會(huì)幫你自動(dòng)生成);這也就是前文中會(huì)爆出編譯錯(cuò)誤的原因(因?yàn)榫幾g器壓根找不到要用的函數(shù)在哪)。

從這里可以看出,union 在語法功能上與 structclass 極其類似:它們都有析構(gòu)函數(shù),也有構(gòu)造函數(shù),也都可以有自己的成員函數(shù);甚至每個(gè)成員分量都可以有自己的訪問控制權(quán)限。

通常來說,一個(gè)這樣的 union 在編譯時(shí)會(huì)這樣的編譯錯(cuò)誤:

#include <string>union U {int integer;double floating;std::string str;
};int main()
{U uni;
} // error: use of deleted function 'U::~U()'

但如果為這個(gè) union 類型添加一個(gè)什么都不做的析構(gòu)函數(shù)和默認(rèn)構(gòu)造函數(shù),就一切都正常了。

#include <string>union U {int integer;double floating;std::string str;U() {}~U() {}
};int main()
{U uni;
} // everything ok

你以為這么簡(jiǎn)單就結(jié)束了嗎?當(dāng)然沒有。不妨再細(xì)想一下:當(dāng)活躍成員是一個(gè) std::string 時(shí),如果需要將活躍成員切換為另一個(gè)分量時(shí),我們是安全的嗎?

3.正確使用 union

這里有個(gè)前提:由于編譯器無從得知一個(gè) union 的當(dāng)前活躍成員是誰,因此自然而然的,union 內(nèi)的對(duì)象的析構(gòu)函數(shù)永遠(yuǎn)不會(huì)自動(dòng)被執(zhí)行。

因?yàn)?union 可以被作為參數(shù)在不同函數(shù)調(diào)用棧間傳遞與修改,因此通過追蹤代碼流走向,進(jìn)而查出一個(gè) union 的當(dāng)前活躍成員絕對(duì)是一件不可能的事情。

這就導(dǎo)致了,當(dāng) union 的活躍成員從一個(gè)非平凡成員上切走時(shí),我們必須主動(dòng)調(diào)用該成員的析構(gòu)函數(shù);如果不這樣做,答案自然是內(nèi)存泄漏(因?yàn)檫@種操作打破了 RAII 保證)。

而當(dāng)我們將 union 切換到另一個(gè)非平凡成員分量時(shí),在除了創(chuàng)建該 union 以外的情景下,都必須使用 placement new 的方式在指定地址調(diào)用構(gòu)造函數(shù)。

必須使用 placement new 是因?yàn)?#xff1a;在 cpp 標(biāo)準(zhǔn)定義中,任何對(duì)象在被聲明后都一定被構(gòu)造完畢(可能是通過默認(rèn)無參構(gòu)造,也可能是通過參數(shù)構(gòu)造),總之該對(duì)象所處的內(nèi)存區(qū)域的數(shù)據(jù)必然有效且良定義;

union 本身只能被視作是一塊存有無序數(shù)據(jù)的內(nèi)存,因此位于其上的對(duì)象是完全不存在的,這樣的對(duì)象可能處于任何狀態(tài);此時(shí)如果試圖調(diào)用移動(dòng)構(gòu)造函數(shù)覆蓋原有數(shù)據(jù)自然也是不符合標(biāo)準(zhǔn)的。

這就導(dǎo)致了正確使用 union 的代碼極其割裂和丑陋。

#include <string>
#include <iostream>template<typename T, typename E>
union UnionLike { // 沒錯(cuò),union 當(dāng)然可以模板化T result_value_;E error_info_;UnionLike( T value ) : result_value_ { move( value ) } {}UnionLike( E error ) : error_info_ { move( error ) } {}~UnionLike() {}
};int main()
{UnionLike<int, std::string> result( "Unknown" ); // 創(chuàng)建時(shí)不需要 placement newstatic_assert(sizeof( result ) == std::max( sizeof( std::string ), sizeof( int ) ));// 沒問題std::cout << result.error_info_ << std::endl;// 未定義行為// std::cout << result.result_value_ << std::endl;// 切換活躍成員之前必須主動(dòng)調(diào)用析構(gòu)函數(shù)result.error_info_.~basic_string();// 然后通過 placement new 在原地址上構(gòu)造新對(duì)象new (&result) int( 42 ); // 當(dāng)然,對(duì)于平凡類型不必如此cout << result.result_value_ << endl;// here is definitely an UB// std::cout << result.error_info_ << std::endl;
}

因此通常來說,要想安全使用 union 都需要使用一個(gè) class 做一遍封裝。

令人高興的是,自 cpp17 后標(biāo)準(zhǔn)庫中有了 std::variant,這就是一個(gè)類型安全的 union;而在 cpp17 以前,則可以選擇 boost::variant 作為代餐。

至于 std::variant 是如何實(shí)現(xiàn)的,就是一個(gè)相當(dāng)復(fù)雜的問題了(我也不想知道);感興趣的可以打開自己的 STL 頭文件慢慢看,反正 cpp 模板庫都是開源的(逃)。

#include <variant>
#include <iostream>int main()
{std::variant<int, std::string> result( "Unknown" );// 因?yàn)閷?shí)現(xiàn)機(jī)制的問題,所以求 std::variant 的實(shí)際大小時(shí)需要減去一個(gè)指針的長(zhǎng)度static_assert((sizeof( result ) - sizeof( void* )) == std::max( sizeof( std::string ), sizeof( int ) ));// 但和 cpp 中其他泛型容器一樣,東西放進(jìn)去容易,取出來很麻煩// 可以獲取當(dāng)前活躍成員所在的索引下標(biāo)std::cout << "Index of: " << result.index();// 然后通過指定類型與 std::get 訪問對(duì)應(yīng)成員,但如果活躍成員不是這個(gè)類型,就會(huì)拋出異常std::cout << " is value of: " << std::get<std::string>( result ) << std::endl;result = 42; // 使用賦值運(yùn)算符直接切換活躍成員,不需要手動(dòng)析構(gòu)成員// 也可以使用訪問器std::visit( []( auto&& arg ) { std::cout << arg << std::endl; }, result );
}

不過如果能確保使用 union 時(shí)都是一些非常底層的場(chǎng)景,從頭到尾都在干一些臟活而不會(huì)向 union 中填入非平凡類型的話,大膽使用 union 就好了,畢竟即使是“零抽象開銷”的標(biāo)準(zhǔn)庫也不是真的完全是毫無開銷的。


  1. 與之相對(duì)的,元組(或者是 c/cpp 的結(jié)構(gòu)體)是一種“積類型”,也就是可以在不同空間、同一時(shí)間存入不同數(shù)據(jù)。 ??

  2. 更多時(shí)候像是一種毫無約束的自由;而放縱的自由就意味著混亂。 ??

  3. 分別是:默認(rèn)構(gòu)造函數(shù)、復(fù)制構(gòu)造函數(shù)、移動(dòng)構(gòu)造函數(shù)、復(fù)制賦值運(yùn)算符、移動(dòng)賦值運(yùn)算符和析構(gòu)函數(shù)。 ??

http://www.risenshineclean.com/news/3416.html

相關(guān)文章:

  • 杭州怎么做網(wǎng)站今日新聞?lì)^條熱點(diǎn)
  • wordpress 插件 支付搜索引擎關(guān)鍵詞優(yōu)化有哪些技巧
  • 離石做網(wǎng)站的公司做網(wǎng)絡(luò)推廣可以通過哪些渠道推廣
  • 門戶網(wǎng)站的建設(shè)思路百度網(wǎng)站排名怎么提高
  • 企業(yè)免費(fèi)網(wǎng)站系統(tǒng)下載地址百度競(jìng)價(jià)推廣什么意思
  • wordpress原始分頁共seo關(guān)鍵詞優(yōu)化費(fèi)用
  • 相冊(cè) wordpressaso如何優(yōu)化
  • c 做網(wǎng)站簡(jiǎn)單嗎百度推廣怎么添加關(guān)鍵詞
  • 做網(wǎng)絡(luò)推廣的技巧網(wǎng)站優(yōu)化排名易下拉效率
  • 浦口區(qū)網(wǎng)站建站杭州seo渠道排名
  • 紅色專題網(wǎng)站首頁模板長(zhǎng)春建站程序
  • 我的網(wǎng)站dedeapp推廣之家
  • wordpress媒體1m以上seo排名快速上升
  • 淘寶客導(dǎo)購(gòu)網(wǎng)站模板seo排名首頁
  • 鄭州做網(wǎng)站推廣運(yùn)營(yíng)商寧波品牌網(wǎng)站推廣優(yōu)化公司
  • 網(wǎng)站建設(shè)模板代碼下載蘇州百度 seo
  • 深圳做微信商城網(wǎng)站建設(shè)蘇州seo營(yíng)銷
  • 找事做搜索網(wǎng)站java培訓(xùn)機(jī)構(gòu)
  • 怎樣制作購(gòu)物網(wǎng)站 微信轉(zhuǎn)發(fā)網(wǎng)站seo分析報(bào)告
  • wap端和app有什么區(qū)別全面落實(shí)疫情防控優(yōu)化措施
  • 廣西建設(shè)監(jiān)理協(xié)會(huì)官網(wǎng)站ui設(shè)計(jì)公司
  • 經(jīng)典wordpress網(wǎng)站寧波網(wǎng)站推廣代運(yùn)營(yíng)
  • 做企業(yè)網(wǎng)站市場(chǎng)分析陜西整站關(guān)鍵詞自然排名優(yōu)化
  • 怎么用ps制作個(gè)人網(wǎng)站模板下載seo培訓(xùn)學(xué)什么
  • 金融保險(xiǎn)網(wǎng)站模板網(wǎng)絡(luò)廣告類型
  • 網(wǎng)站里的圖片切換怎么做網(wǎng)絡(luò)營(yíng)銷推廣策略
  • 萬互網(wǎng)站建站sem搜索引擎
  • wap網(wǎng)站多少錢百度知道官網(wǎng)登錄入口
  • 株洲 網(wǎng)站建設(shè)百度關(guān)鍵詞優(yōu)化詞精靈
  • 手機(jī)微信網(wǎng)站模板買賣交易平臺(tái)