IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 在class中初始化vector成员发生的most vexing parse问题 -> 正文阅读

[C++知识库]在class中初始化vector成员发生的most vexing parse问题

前言

在class中带容量初始化vector时,发生报错,Expected parameter declaratorExpected ')',我寻思着我括号都敲对了啊,怎么就出问题了?加上初始值,还是报错,然后准备删掉初始值和size时,才发现我好像声明了个函数……真坑,规范编程太重要了。

class Solution {
private:
    // vector<int> v1(10); // 错误
    // vector<int> v1(10, 0); // 错误
    // vector<int> v1(); // 仔细一看,这不是声明了个空参返回vector的v1函数吗!所以前两行错误的原因是编译器识别v1为函数而10又不是任何一种type
	[...]
}

有个术语专门指代这种情况:most vexing parse,即最令人烦恼的解析,是C++中一种反直觉的二义解析形式。简单说就是,在编译器无法区分某语句是初始化对象参数还是声明一个函数时指定参数类型时,就会将该行解释为函数声明。除了初始化vector以外还有好多情况会出现这种MVP。

先说结论

那么如何这样带参数初始化呢?

C++11以后,有了统一初始化(Uniform initialization),可以用大括号完成我们想要的效果,此外还有第二种赋值初始化。

class Solution {
private:
	vector<int> v1{vector<int>(10, 0)}; // 第二个参数缺省为0
    vector<int> v2 = vector<int>(10, 0); // 第二个参数缺省为0
	[...]
}

需要注意:vector<int> v1{10}是按元素初始化,只会初始化一个元素10;

在C++11之前,就没有这种初始化方式了,我们必须老老实实在构造函数里面初始化,可以用初始化列表或者vector的resize函数:

// 方法一:
class Solution {
private:
    vector<int> v1;
	[...]
public:
    Solution() : v1(10, 0) {} // 在构造函数初始化列表里面初始化
}

// 方法二:
class Solution {
private:
    vector<int> v1;
	[...]
public:
    Solution() {
        v1.resize(10, 0); // 在构造函数中用resize函数
    }
}

从兼容性来说,还是方法二最合适。

细说一下MVP

好,我们不能只满足于解决了初始化问题,来细看一下这个MVP到底是个啥,以及如何避免。

看Wiki给的一个例子:

struct Timer {};

struct TimeKeeper {
  explicit TimeKeeper(Timer t);
  int get_time();
};

int main() {
  TimeKeeper time_keeper(Timer()); // 这里有歧义
  return time_keeper.get_time();
}

在代码中标注一行中的time_keeper可以有两种解释:

  1. 一个TimeKeeper类型的变量,用类Timer的默认构造函数初始化;这也是我们想实现的

  2. 一个函数time_keeper,返回值是TimeKeeper类型,有一个函数参数,等价为一个指针参数,该指针指向Timer的匿名构造函数。(见注释)

    注:根据C++类型退化规则,作为参数声明的函数等价于一个指向同类型函数的指针。参见C++函数对象的实例

C++标准中采取第二种解释,将这种MVP情况统一解释为函数,导致出错。

如何避免MVP

自C++11以后,首选方法是使用统一初始化:

// 以下均可
TimeKeeper time_keeper(Timer{});
TimeKeeper time_keeper{Timer()};
TimeKeeper time_keeper{Timer{}};
TimeKeeper time_keeper(     {}); // 甚至允许完全省略类型名称
TimeKeeper time_keeper{     {}};

在C++11之前,强制获得预期解释的常用手段是使用额外括号拷贝初始化,后一种写法更常见,而且可能被编译器优化,C++17开始,可以保证这种优化。

TimeKeeper time_keeper( (Timer()) ); // 额外括号
TimeKeeper time_keeper = TimeKeeper(Timer()); // 拷贝初始化

结语

总之结论就是,留意这种MVP,并在coding中避免MVP,对我自己来说以后除了写算法题还是老老实实在构造函数的初始化列表里面初始化吧。

参考资料:

  1. C++统一初始化.
  2. 最令人烦恼的解析MVP
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:22:52  更:2022-05-09 12:24:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:17:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码