首页 > 编程语言 >Modern C++——不准确“类型声明”引发的非必要性能损耗

Modern C++——不准确“类型声明”引发的非必要性能损耗

时间:2024-09-01 14:57:13浏览次数:11  
标签:std map Modern C++ Custom 编译器 unordered 非必要

大纲

C++是一种强类型语言。我们在编码时就需要明确指出每个变量的类型,进而让编译器可以正确的编译。看似C++编译器比其他弱类型语言的编译器要死板,实则它也做了很多“隐藏”的操作。它会在尝试针对一些非预期类型进行相应转换,以符合预期,比如《C++拾趣——类构造函数的隐式转换》中提到的隐式转换。

但是也正因为这些“隐藏”的转换行为,让一些行为超出我们的预期。比如本文提及的案例,就是因为我们声明了一个不准确的类型变量,导致编译器为了让我们代码“合法”,进而做了一些隐式转换,导致程序性能下降。

我们也将通过这个案例,了解C++11引入auto关键字的必要性。

案例

先看下面这段可以运行的代码。

    std::cout << "Create unordered_map" << std::endl;

    std::unordered_map<Custom, int> unordered_map;
    unordered_map[std::move(Custom(1))] = 1;
    unordered_map[std::move(Custom(2))] = 2;
    unordered_map[std::move(Custom(3))] = 3;

    std::cout << std::endl << "Traverse unordered_map using std::pair<Custom, int>" << std::endl;

    for (const std::pair<Custom, int>& pair : unordered_map) {
        std::cout << pair.first << " " << pair.second << std::endl;
    }

请问下面的代码有什么性能问题?

可能第一眼看过去,并不能发现它的问题所在。我们将这段代码的运行过程打印出来
在这里插入图片描述
可以发现在遍历的过程中,发生了Custom对象的复制和析构。

如果Custom对象比较大,就会引发性能问题。

这是因为std::unordered_map的Key是const类型,即我们应该如下方式遍历

    for (const std::pair<const Custom, int>& pair : unordered_map) {
        std::cout << pair.first << " " << pair.second << std::endl;
    }   

编译器在发现我们没有使用const Custom时,会自己推理并转换以符合我们书写的代码。这样就会导致一次const Custom向Custom复制的一次构造。

正因为这些犄角旮旯的知识导致编写健壮高效的C++代码比较困难。但是在C++11中引入的auto就可以很大的缓解我们的心智负担。我们可以这么写上述代码

    for (const auto& pair : unordered_map) {
        std::cout << pair.first << " " << pair.second << std::endl;
    }

这样编译器会帮我们推导出正确的类型。
在这里插入图片描述

代码地址

https://github.com/f304646673/cpulsplus/tree/master/traverse_unordered_map

标签:std,map,Modern,C++,Custom,编译器,unordered,非必要
From: https://blog.csdn.net/breaksoftware/article/details/141333333

相关文章

  • c++ I/O
    1.flush刷新缓存,endl刷新缓存并换行cout<<"Hello"<<fulsh;cout<<"Wait<<endl;2.hex,oct,dec输出16进制,8进制,10进制cout<<hexcout<<octcout<<dec3.使用width调节宽度cout.width(12);//width函数只影响下一个要显示的item4.使用fill填充字符。C++默认......
  • C++ 标准输入输出 -- <iostream>
    <iostream>库是C++标准库中用于输入输出操作的头文件。<iostream>定义了几个常用的流类和操作符,允许程序与标准输入输出设备(如键盘和屏幕)进行交互。以下是<iostream>库的详细使用说明,包括其主要类和常见用法示例。主要类std::istream:用于输入操作的抽象基类。std::ostre......
  • C++奇迹之旅:深度解析list的模拟实现
    文章目录......
  • C++:std::thread 和 pthread
            在C++中,线程的实现主要有两种方式:使用C++11标准库中的std::thread和POSIX线程库(pthread)。这两种方式各有优缺点,适用于不同的场景。以下是对这两种方式的详细比较和示例代码。std::thread示例代码#include<iostream>#include<thread>#include<chrono>......
  • C++:std::this_thread::sleep_for 和 sleep
            在C++中,std::this_thread::sleep_for和sleep函数都可以用来使当前线程暂停执行一段时间,但它们有一些重要的区别。以下是对这两种方法的详细比较:std::this_thread::sleep_for定义:std::this_thread::sleep_for是C++11标准库中的一个函数,用于使当前线程暂停执......
  • C++面向对象编程(OOP)教程
    C++面向对象编程(OOP)教程在C++中,面向对象编程(OOP)是一种编程范式,它基于“对象”的概念来设计软件。OOP强调将数据(属性)和操作这些数据的方法(行为)封装在一起,形成对象。这种封装提高了代码的模块化、可重用性和可维护性。C++通过类(Class)、对象(Object)、继承(Inheritance)、封装(Encapsu......
  • c++ STL常用容器使用(vector、deque、stack、queue、list、set、map等)
    1、vector使用动态数组,也叫可变数组,容器的空间是动态增长的,当空间不足时,申请更大一块空间,让后将原数据拷贝到新空间中,并释放原空间在这里插入图片描述1.1、初始化操作intarr[]={1,3,2,5};//1、方式一(初始化)vector<int>v1;//容器尾部插入数据v1.push_back(1);v1......
  • C++基础之指针(加精)
    指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。在这种情况下,只能通过指针来访问内存。在C语言中,可以用库函数malloc()来分配内存;在C++中仍然可以这样做,但C++还有更好的方法——new运算符。文章目录指针与数组深入探究探究一探究二探究三探究四探究五探......
  • opencv/c++的一些简单的操作(入门)
    目录读取图片读取视频读取摄像头图像处理腐蚀膨胀调整图像大小裁剪和缩放 绘制绘制矩形绘制圆形绘制线条透视变换颜色检测轮廓查找人脸检测检测人脸检测嘴巴可适当调整参数读取图片读取路径widows使用vissto一定是\斜杠#include<opencv2/imgcodec......
  • 前K个高频单词 C++
    给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。示例1:输入:words=["i","love","leetcode","i","love","coding"],k=2输出:["i","......