CLKing31--------------------------[C++] 关于operator[]()和at()

[C++] 关于operator[]()和at()

RaydeLee 2018-09-10 13:26:39  8614  收藏 6
分类专栏: C++
版权
在接触到STL时,我发现大部分容器都有两个成员函数:operator[]()和at()。乍一看,这实现的不就是同一种功能,为什么要存在两个函数?我们去www.cplucplus.com看一看。

<array>
array


<deque>
deque


<forward_list>
forward_list


<list>
list


<map>


map


multimap


<queue>


priority_queue


queue


<set>


multiset


set


<stack>
stack


<unordered_map>


unordered_map


unordered_multimap


<unordered_set>


unordered_multiset


unordered_set


<vector>


vector


vector<bool>


不仅仅是容器类,std::string和std::basic_string中也同时存在operator[]()函数和at()函数。

basic_string


string


从以上众多截图中可以看出:array、deque、map、unordered_map、vector、basic_string和string类中同时存在operator[]()和at(0函数(可能其他类中也有,但是本文只研究这么多:D)。

引入operator[]()的原因,我认为是为了增强代码的可读性,并且用户使用起来也更加方便,更像是在使用c语言中的数组。

接下来上一些代码吧:

/*code block 1*/
int main() {
    std::array<int, 5> iArray;
 
    std::cout << iArray.at(6) << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iArray[6] << std::endl;
 
    return 0;
}


代码块1的运行结果如上图所示。

我们定义了一个大小为5的array,元素类型为int。位置为6的元素实际上不存在,代码分别使用at()和operator[]()对其访问。为了使结果更加明显,中间加入了分割线。

调用at()方法,如果下标越界,会使程序抛出一个std::out_of_range的异常。

而调用operator[]方法,如果下标越界,程序会崩溃。

你以为我写了这么多,贴了这么多图,就为了告诉你这个吗?当然不仅仅这些……

/*code block 2*/
int main() {
    std::deque<int> iDeque;
 
    std::cout << iDeque.at(6) << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iDeque[6] << std::endl;
 
    return 0;
}


代码块2的运行结果如上图所示,可以看出,运行结果与代码块1没有太大的区别。这也说明了deque和array这两个函数的功能是一致的。

/*code block 3*/
int main() {
    std::deque<int> iDeque;
 
    iDeque.resize(5);
    std::cout << iDeque.at(6) << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iDeque[6] << std::endl;
 
    return 0;
}
代码块3的运行结果与代码块2的运行结果完全一致。

/*code block 4*/
int main() {
    std::map<int, std::string> isMap;
 
    isMap[1] = "1";
    std::cout << "-------------" << std::endl;
    isMap.at(2) = "2";
 
    return 0;
}


代码块4的运行结果如上图所示。wait,wait,wait!!!怎么会这样?map使用operator[]并没有出错,程序打印出了分隔符,接下来对at()的使用抛出了异常。但是,为什么停止工作?难道之前的猜想都是错的?

对map使用mapName[key] = value,实际上是生成一个键值对(make_pair(key, value)),将该键值对插入到map中。所以对map使用operator[]()函数不会导致错误(前提是key和value的类型要与定义一致)。

主要代码只保留一句isMap.at(2); 编译、运行、查看结果,发现运行结果与代码块4的运行结果不变。说明这次的程序崩溃是由at()函数引起的,在崩溃之前,它还抛出了std::out_of_range异常。

那么,以前的种种猜想是不是错了呢?回顾之前的代码并稍作修改:

/*code block 5*/
int main() {
    std::array<int, 5> iArray;
 
    iArray.at(5) = 5;
}
代码块5运行出的结果既抛出了std::out_of_range异常,又停止了工作。我们是不是冤枉了operator[]()?

/*code block 6*/
int main() {
    std::array<int, 5> iArray;
 
    iArray[6] = 6;
 
    return 0;
}


代码6的运行结果如上图,当点击了“关闭程序”后,命令行显示如下:

说明我们没有冤枉operator[](),它对下标的不当操作也会导致程序停止工作。

/*code blocks 7*/
int main() {
    std::deque<int> iDeque;
 
    iDeque[16] = 5;
    std::cout << iDeque.size() << std::endl;
    std::cout << iDeque[16] << std::endl;
    std::cout << iDeque.at(16) << std::endl;
 
    return 0;
}
在代码块中,首先输入iDeque[16] = 5,编译,程序能够正常运行,这已经与array有所不同了。

接下来,我想看看deque的大小是否改变了,结果输出依然为0。

再输入iDeque[16]的值,可以正常输出,是5.

加入最后一句,运行结果如下:

事实上,内存中iDeque[16]的位置上的值为5,at()函数崩溃是因为它在调用时做了下标检查,因为iDeque的size()为0,所以16这个下标是无效的,所以抛出了std::out_of_range异常。

/*code block 8*/
int main() {
    std::unordered_map<int, std::string> isUnorderedMap;
 
    isUnorderedMap[3] = "three";
    std::cout << isUnorderedMap.size() << std::endl;
    std::cout << isUnorderedMap[3] << std::endl;
    std::cout << isUnorderedMap.at(3) << std::endl;
 
    return 0;
}


代码块8的运行结果如上图所示,在使用operator[]对isUnorderedMap中添加元素之后,用at()函数可以正常访问到该元素。试图用at()函数去添加元素时,程序抛出std::out_of_range异常。

/*code block 9*/
int main() {
    std::vector<int> iVector;
 
    iVector[2] = 5;
 
    return 0;
}


代码块9的运行结果如山图所示,虽然只有简单的一行代码,仍然使得程序停止了。因为iVector是一个空的vector,而vector不支持用这种方式添加元素,所以程序停止工作。

​​/*code block 10*/
int main() {
    std::vector<int> iVector;
 
    iVector.at(3) = 5;
 
    return 0;
}


代码块10的运行结果如上图,程序抛出了std::out_of_range异常。

/*code block 11*/
int main() {
    std::vector<int> iVector(5);
 
    iVector.at(3) = 5;
    iVector[2] = 9;
    std::cout << "-------------" << std::endl;
    std::cout << iVector[5] << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iVector.at(5) << std::endl;
 
    return 0;
}


代码块11的运行结果如上图,可以看出,虽然iVector只有5个元素,但是使用operator[]()访问位置为5的元素不会出错,因为operator[]()没有做下标有效性检查。使用at()函数访问位置为5的元素,因为进行了下标的有效性判断,所以抛出了std::out_of_range异常。

/*code block 12*/
int main() {
    std::vector<int> iVector;
 
    iVector.reserve(8);
    std::cout << iVector.size() << std::endl;
    std::cout << iVector.capacity() << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iVector[5] << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << iVector.at(5) << std::endl;
 
    return 0;
}


代码块12的运行结果如上图。通过调用reserve()方法,将iVector的capacity改为8,然而size还是0,所以通过at()访问会抛出std::out_of_range异常,而使用operator[]()访问则不会。

/*code block 13*/
int main() {
    std::string  str1 = "str1";
 
    std::cout << str1.size() << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << "[" << str1[str1.size()] << "]" << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << "[" << str1.at(str1.size()) << "]" << std::endl;
 
    return 0;
}


代码块13的运行结果如上图所示。str1长度为4,用operator[]()访问位置为4的元素,输出为一个空格字符(也有可能为其他字符)。用at()访问位置为4的元素,抛出std::out_of_range异常。

/*code block 14*/
int main() {
    std::basic_string<char>  str = "str";
 
    std::cout << str.size() << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << "[" << str[str.size()] << "]" << std::endl;
    std::cout << "-------------" << std::endl;
    std::cout << "[" << str.at(str.size()) << "]" << std::endl;
 
    return 0;
}


代码块14的运行结果如上图,std::basic_string是模板类,运行结果与代码块13一致,这里不再赘述。

总结
STL提供的容器中:

array、deque、vector不能通过operator[]()向容器中添加元素。

map、unordered_map类可以通过operator[]向容器中添加元素。

以上容器均不能通过at()函数向容器重添加元素。

at()函数在被调用时,会检查下标的有效性(与容器的size()比较而不是capacity()(例如vector)),若下标有效则返回对应位置的元素,否则抛出std::out_of_range异常。

operator[]()函数在被调用时,不检查下标的有效性。

例外:对于array而言,无论使用operator[]还是at()都会做下标有效性检查(代码块6)。

注:以上所有代码均使用code::blocks17.12进行编译。

注:转载请注明出处,谢谢。


点赞
6

评论
3

分享

收藏
6

举报
————————————————
版权声明:本文为CSDN博主「RaydeLee」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37474728/article/details/82586068

猜你喜欢

转载自blog.csdn.net/qq_43662480/article/details/114643733
今日推荐