一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(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++為什么不能修改set里的值?非要修改怎么辦?

C++為什么不能修改set里的值?非要修改怎么辦?

2022-02-19 16:19Coder_LT C/C++

因為之前的文章有說過C++中 set的介紹及用法,今天這篇文章我們就來說說C++為什么不能修改set里的值,如果非要修改的話應(yīng)該怎么辦,下面我們一起進入文章看看下面內(nèi)容,需要的朋友可以參考以下,希望對你有所幫助

在上一期C++中 set的用法文章當(dāng)中講解了set的一些常規(guī)用法和api,最后末尾的時候留了一個問題,如何修改set中的元素?今天就來聊聊這個問題。

很多同學(xué)估計會說,這還不簡單,不是有迭代器么。我們把迭代器當(dāng)做指針,去修改它指向的值不就行了嗎?

like this:

set<string> st{"hello", "world", "good"};
set<string>::iterator it = st.begin();
*it = "test";

但是很遺憾,你真這么做了,會得到一個報錯:

C++為什么不能修改set里的值?非要修改怎么辦?

報錯的意思是set的迭代器并沒有重載等于符號,也就是說我們沒辦法使用等于符號來為它賦值。說白了,也就是編譯器進行了限制,不允許我們對set迭代器的內(nèi)容進行修改。

Effective C++當(dāng)中也明確說了,不要對set集合中的元素進行修改。

不知道有沒有小伙伴去嘗試,可能有些小伙伴嘗試了之后會說不對啊,在我電腦上怎么能運行?

也很簡單,大概率因為你用的是vc編譯器,比如臭名昭著的VC6.0或者是visual studio IDE(不是VSCode)。微軟的編譯器沒有嚴(yán)格遵循C++的標(biāo)準(zhǔn),在很多地方有些瑕疵和隨意。這也是不推薦使用VC6.0進行C++學(xué)習(xí)的原因,因為時間久了,就把錯的當(dāng)成對的了。

吐槽完畢,回到正題。既然已經(jīng)知道了這樣修改會引發(fā)報錯,是不是就已經(jīng)得到了答案了呢?

其實并沒有,因為如果我們真的去閱讀C++的標(biāo)準(zhǔn)或者是翻閱set的源碼,會發(fā)現(xiàn)其中是沒有明確說明set中的元素是定義成const的。

實際上,std::set<T>聲明一個allocator_type,默認(rèn)為std::allocator<T>。std::allocator_traits<allocator_type>::construct將它傳遞給T *,從而構(gòu)造一個T,而不是const T。

說人話就是std::set<T>其實不允許將元素定義成const,既然元素不是const類型,那么就說明理論上是可以修改的。也就是說C++規(guī)范里說不能改,Effective C++中說建議不要改,但實際上底層的實現(xiàn)里并沒有嚴(yán)格禁止。我們非要改還是有辦法的,那是什么辦法呢?

老梁縱觀全網(wǎng)博客,也沒有看到一篇把這個問題說清楚。

在我們開始之前,首先思考一個問題,既然set底層源碼當(dāng)中的元素并不是定義成const,那么當(dāng)我們?nèi)ビ玫魅バ薷牡臅r候為什么會報錯呢?

要回答這個問題,我們只需要查看一下set迭代器的源碼定義即可。

老梁在大牛的源碼分析當(dāng)中找到了一行關(guān)鍵的代碼:

C++為什么不能修改set里的值?非要修改怎么辦?

原來迭代器的定義是一個const_iterator,搞了半天,其實并不是set底層限制了禁止修改,而是通過迭代器限制的。所以要想修改set當(dāng)中的元素,我們只需要繞開迭代器的這個限制即可。

進一步研究可以發(fā)現(xiàn),它這里使用的是一個const_iterator,它表示一個指向常量的迭代器,和const iterator不同。后者表示迭代器本身是一個常量,即迭代器本身指向的位置不能修改。而前者表示迭代器指向的位置是一個const常量,迭代器本身可以修改,指向不同的位置,但我們不能修改它指向的位置的值。

const_iterator并沒有嚴(yán)格限制只能指向const修飾的變量,這也就能解釋為什么set當(dāng)中的元素沒有const修飾也不會報錯的原因,因為const_iterator兼容這種情況。

const_iterator解引用之后是一個const修飾的變量的引用,所以我們要對它指向的內(nèi)容進行修改,只需要將它解引用的結(jié)果去除const限制即可。那具體怎么操作呢,我們可以使用const_cast操作符解除const的限制。

但它也不是萬能的,它只能使用在引用和指針當(dāng)中,用來去掉const屬性。

這里有必要說明一下,在C++當(dāng)中const修飾符出現(xiàn)的位置不同有不同的含義。以指針舉例,const T* p和T* const p是兩種完全不同的指針,前者表示不能通過指針去修改指向?qū)ο蟮膬?nèi)容。如p->x = 100;這樣的操作都是非法的。而后者表示指針只能在初始化時設(shè)置指向的內(nèi)容,之后不能修改指向,如p=&t;是非法的。

在當(dāng)前問題當(dāng)中,我們想要修改set當(dāng)中的元素值,遇到了const限制,顯然是第一種情況。

有些同學(xué)可能會覺得疑惑,我們加上const的目的不就是為了對變量做限制,從而可以在編譯的時候通過編譯器來替我們檢查一些非法的操作嗎?既然如此,又為什么需要去掉呢?

主要的原因是有時候我們手上的變量有const修飾,但是我們想要調(diào)用一個函數(shù),而函數(shù)的內(nèi)部會對指針或引用指向的值進行修改。這個時候我們就沒辦法傳入我們手上已有的參數(shù)了,const_cast操作符設(shè)計的初衷就是為了應(yīng)對這種情況。

我們來舉個例子:

void test(int *x) {
*x = 5;
}

int main() {
int a = 3;
const int *p = &a;

test(p);
return 0;
}

如果我們編譯上面這段代碼就會遇到編譯器無情地報錯,因為我們在test函數(shù)內(nèi)部修改了指針p的指向。

C++為什么不能修改set里的值?非要修改怎么辦?

這個時候我們就可以在傳參的時候,使用const_cast操作符來解除掉const的限制。

test(const_cast<int*>(p));

尖括號中是我們要轉(zhuǎn)換的類型,只能是指針或引用。如果我們輸出指針p指向的值,會得到5,因為在test函數(shù)當(dāng)中進行了修改。

看起來好像很簡單,對吧?

但是我們接下來看兩個例子,可能會令人有些費解:

const int a = 3;
int *r = const_cast<int*>(&a);
(*r)++;
cout << a << endl;

int i = 3;
const int b = i;
int *r2 = const_cast<int*>(&b);
(*r2)++;
cout << b << endl;

這兩段代碼做的事情非常類似,也就是通過const_cast修改了一個const修飾的int。唯一的不同是int a是直接賦值成了3,而int b是賦值成了另外一個也等于3的int。這兩者其實并沒有什么區(qū)別,對吧?但是當(dāng)我們運行代碼之后,神奇的事情發(fā)生了,

屏幕上輸出的結(jié)果是這樣的:

C++為什么不能修改set里的值?非要修改怎么辦?

為什么一個是3,另外一個是4呢?這兩者的邏輯明明是一樣的!

老梁發(fā)現(xiàn)這個問題的時候是完全震驚的,查了好久的資料,才從大牛博客的只言片語當(dāng)中找到了一點描述。原來是編譯器針對第一種情況做了優(yōu)化,因為a初始化時給的是一個常量,所以當(dāng)我們輸出的時候,編譯器就直接取了3代替了它實際原本應(yīng)該的值。

關(guān)于這個解釋老梁也不能完全確認(rèn),如果有知道的小伙伴不妨在下方留言。

最后, 我們回到正題,如果我們想要修改set當(dāng)中的元素,可以怎么操作呢?

我們知道了const_cast操作符之后就完全沒有懸念了。

set<string> st{"hello", "world", "good"};
set<string>::iterator it = st.begin();
const_cast<string&>(*it) = "test";

for (auto it = st.begin(); it != st.end(); it++) {
  cout << *it << endl;
}

但是我們需要注意一點,我們這樣強行修改其實是沒有經(jīng)過set原本的機制的。也就是說我們雖然改了元素的值,但是它在紅黑樹中的位置其實是沒有變的。這樣的結(jié)果就是會導(dǎo)致元素失去有序性,比如上面的結(jié)果輸出的順序是:"test","hello","world",按道理應(yīng)該是按照字典順序排序的。

這也是為什么C++ Primer里強烈建議大家不要修改set中元素值的原因,如果真的要修改,只能先刪除再添加了。雖然這樣會犧牲一點點性能,但至少可以保證set里的數(shù)據(jù)都是安全有序的。

到此這篇關(guān)于C++為什么不能修改set里的值?非要修改怎么辦?的文章就介紹到這了,更多相關(guān)C++修改set里的值內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

注:文章轉(zhuǎn)自微信公眾號:Coder梁(ID:Coder_LT)

延伸 · 閱讀

精彩推薦
  • 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++C/C++經(jīng)典實例之模擬計算器示例代碼

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

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

    jia150610152021-06-07
  • C/C++C語言實現(xiàn)電腦關(guān)機程序

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

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

    xiaocaidayong8482021-08-20
  • 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++ 單線程實現(xiàn)同時監(jiān)聽多個端口

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

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

    源之緣11542021-10-27
  • C/C++深入理解goto語句的替代實現(xiàn)方式分析

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

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

    C語言教程網(wǎng)7342020-12-03
  • C/C++學(xué)習(xí)C++編程的必備軟件

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

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

    謝恩銘10102021-05-08
主站蜘蛛池模板: 大东北chinesexxxx露脸 | 超强台风免费观看完整版视频 | 成人免费片 | 久久久91精品国产一区二区 | 99热这里只有精品在线播放 | 美味情缘韩国在线观看视频 | 天天夜夜草草久久伊人天堂 | 日本人在线看片 | 免费国产高清视频 | 国产色综合久久五月色婷婷中文 | 娇女的呻吟亲女禁忌h16 | 天堂网站天堂小说 | h玉足嫩脚嗯啊白丝 | 国产成人精品一区二三区2022 | 亚洲男人网 | 精品湿 | zol中关村在线 | 深夜a| 欧美精品色精品一区二区三区 | 欧美灰丝袜丝交nylons | 亚洲天堂中文字幕 | 国产在线综合网 | 亚洲色图综合网 | 九九99香蕉在线视频免费 | 免费全看男女拍拍拍的视频 | 四缺一写的小说 | 干操网 | 精品福利视频一区二区三区 | 无码区国产区在线播放 | 欧美透逼视频 | 欧美成人免费观看bbb | 九九热免费在线观看 | 91尤物在线| 国产乱子伦真实china | 亚洲国产欧美在线人成aaaa20 | 无码欧美喷潮福利XXXX | 成人免费在线视频观看 | 暖暖中国免费观看高清完整版 | 国产东北3p真实在线456视频 | 亚洲视频一 | 四虎影视紧急入口地址大全 |