在这种情况下,std :: vector如何被初始化?

如何解决在这种情况下,std :: vector如何被初始化?

我最近遇到了一小段代码,使我感到很奇怪。

#include <iostream>
#include <array>
#include <vector>

int main()
{
    std::vector<std::array<int,2>> idx;
    for (auto ii = 0; ii < 2 * 10; ii += 2)
        {
        idx.push_back ({ii,ii + 1});
        }

    auto &ind = reinterpret_cast<std::vector<int> &> (idx);   
    idx.push_back ({ 40,50 });

    for (auto ii: ind)
        {
        std::cout << ii << std::endl;
        }
    
}

我确定代码会给出错误的结果,但是它给了我预期的结果。 一些观察:

  1. 在这种情况下,reinterpret_cast的行为是不确定的。
  2. 这不是很好的代码
  3. 它在我测试过的所有编译器上均可工作。通过工作,我的意思是它给了我很好的结果。

话虽如此,我阅读了VS 2019的std :: vector实现。std::vector::size()的值是根据_Mylast - _Myfirst计算出来的。

我的问题是 _Mylast如何正确初始化?

我阅读了代码,但是找不到。这不是关于不确定行为的问题,而是关于C ++向量的实现。

解决方法

在此实现中,矢量获取大小的方法是:将指针指向最后一个元素,然后从该指针中减去指向数据开头的指针。该结果就是向量中元素的数量。当您使用idx执行此操作时,由于_Mylast11 * sizeof(std::array<int,2>)之间有_Myfirst个字节,因此得到11个。当您使用ind时,_Mylast_Myfirst具有相同的值,因此它们是相同的字节数,但是现在它们是int*而不是{{ 1}},这意味着编译器将根据std::array<int,2>*来处理减法运算,从而得出方程式

sizeof(int)

给出22的“正确”结果。就标准而言,这是所有未定义的行为,但这就是为什么它似乎具有正确的结果的原因。如果vector允许将大小存储为类成员(允许这样做),那么您将从size = 11 * sizeof(std::array<int,2>) / sizeof(int) idx中获得相同的值。

,
  1. UB的典型处理方法是什么都不做,并假设程序员知道他们在做什么,所以即使您错了,它也会采取最小的阻力之路,并继续做正确的事情。
  2. 典型的vector实现为三个指针:一个指向数据存储区(我们将称为datap),一个指向数据存储区的末尾,因此您可以轻松地知道何时要从头开始,需要重新分配以获取更大的数据存储区(称为capp),以及指向该数据存储区中使用的数据结尾的指针(endp)。
  3. 通常,元素的数量是一些通用指针算法endp - datap,它将提供endpdatap之间的元素数量。

Visual Studio遵循典型的实现,因此使用较小的数组,因为我懒于绘制整个该死的东西,所以让我们看一下vector<array<int,2>>的2个元素和4个容量。 / p>

+-------+-------+-------+-------+
|  1    |   2   |   X   |   X   |
+-------+-------+-------+-------+
^               ^               ^
datap           endp            capp

reinterpret_cast用不同的眼光看待事物。它不会更改任何值,并且由于vector的两个视图具有完全相同的成员,并且这些成员具有完全相同的大小datap,因为一个视图与datap位于同一位置对于其他。它将使用另一种类型来解释,在这种情况下,该类型的大小只有一半。 <vector<int>>看起来像

+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | X | X | X | X |
+---+---+---+---+---+---+---+---+
^               ^               ^
datap           endp            capp

大小和容量的两倍。

您可以使用更复杂的结构来执行此操作,但是可能会填充,vtables和其他有趣的东西,从而使包含的int不能完美对齐,这就是为什么人们说不要相信您的结果。 datapendpcapp将始终指向相同的位置,但是如果投射到vector<string>,则大小甚至可能为1。

+-----------------------+-------+
|           1           |
+-----------------------+-------+
^               ^               ^
datap           endp            capp

实际上,vector实现可能没有使用三个指针。 Visual Studio的下一个更新可以实现vector,其中包含用于数据的指针和用于容量和大小的两个整数。如果满足vector的要求,则某些天才可以用独角兽的角,凤凰羽毛和一堆Care Bear填充物实现。该实现也可能超出职责范围,并捕获错误并警告您(Visual Studio在vector的调试版本中正是这样做的,以捕获运算符[]中的越界访问,但是我不知道它怎么会用reinterpret_cast欺骗编译器或入侵五角大楼。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-