当前位置: 首页 > news >正文

定义和初始化 vector 对象(三十八)

1. 常见初始化方式

下面的表 3.4 列出了初始化 vector 对象的常用方法,其中 T 表示 vector 内元素的类型。

语法形式说明
vector<T> v1;默认初始化:创建一个空 vector,v1 不含任何元素;元素类型为 T,后续可通过 push_back 等操作添加元素。
vector<T> v2(v1);直接拷贝初始化:v2 是 v1 的副本,包含 v1 中所有元素;等价于 vector<T> v2 = v1;
vector<T> v2 = v1;拷贝初始化:将 v1 的所有元素拷贝给 v2。
vector<T> v3(n, val);直接初始化:创建一个包含 n 个元素的 vector,每个元素都被初始化为 val。
vector<T> v4(n);直接初始化:创建一个包含 n 个值初始化的元素的 vector。对内置类型来说,每个元素值为 0;对类类型,则调用默认构造函数。
vector<T> v5{a, b, c, ...};列表初始化:使用花括号将若干初始值列表传入,v5 的元素个数即为列表中初始值的个数,每个元素依次赋值为相应的初始值。
vector<T> v5 = {a, b, c, ...};拷贝列表初始化:效果等同于列表初始化,v5 被初始化为包含 a, b, c… 的 vector 对象。

例如:

#include <vector>
#include <string>
#include <iostream>
using std::vector;
using std::string;
using std::cout;
using std::endl;

int main() {
    // 默认初始化:创建一个空 vector,对象中没有元素
    vector<string> svec;
    
    // 直接拷贝初始化:v2 包含 svec 中所有元素的副本(此时 svec 为空,所以 v2 也为空)
    vector<string> v2(svec);
    vector<string> v2_2 = svec; // 等价于 v2(svec)

    // 创建一个包含 10 个元素的 vector,每个元素均初始化为 "hi!"
    vector<string> v3(10, "hi!");
    
    // 创建一个包含 10 个元素的 vector,每个元素为值初始化
    vector<int> v4(10); // 对于 int,值初始化的结果为 0

    // 列表初始化:使用 initializer_list 创建 vector
    vector<string> v5{"a", "an", "the"};
    vector<string> v5_2 = {"a", "an", "the"};  // 等价于列表初始化

    // 输出部分内容以验证
    cout << "v3 size: " << v3.size() << endl;   // 输出 10
    cout << "v4 elements: ";
    for (auto n : v4)
        cout << n << " "; // 每个元素为 0
    cout << endl;
    cout << "v5 contents: ";
    for (const auto &s : v5)
        cout << s << " "; // 输出 a an the
    cout << endl;

    return 0;
}

2. 关于拷贝初始化与直接初始化的讨论

C++ 中提供了两种主要的初始化方式:

  • 直接初始化 (Direct Initialization):不使用等号,例如
    vector<int> v1(10);      // 创建一个包含 10 个 int 元素的 vector,使用直接初始化
    vector<int> v3(10, 1);   // 创建一个包含 10 个 int 元素,每个元素的值均为 1
    
  • 拷贝初始化 (Copy Initialization):使用等号,例如
    vector<int> v2 = v1;     // 将 v1 的元素拷贝到 v2 中
    vector<int> v5 = vector<int>(10, 1);  // 显式创建临时对象再拷贝给 v5
    

对于只有一个初始值(例如字符串字面值或已有 vector 对象)的情况,直接初始化与拷贝初始化效果通常是一样的。但当涉及多个初始参数时(例如指定元素数量和统一初始值),直接初始化更为直观,拷贝初始化则需要显式创建临时对象,读起来较为冗长且可读性较差。

3. 列表初始化与圆括号初始化的区别

在 C++11 中,除了传统的圆括号初始化,还可以使用花括号来进行列表初始化。列表初始化的含义取决于所提供初始值的数量和类型,常见的区别如下:

  • 单个整数值

    • vector<int> v1(10);
      解释:v1 被直接初始化为 10 个元素,每个元素均值初始化(对于 int,初始值为 0)。
    • vector<int> v2{10};
      解释:v2 被列表初始化,列表中只有一个元素 10,所以 v2 有一个元素,其值为 10。
  • 两个整数值

    • vector<int> v3(10, 1);
      解释:v3 包含 10 个元素,每个元素的值均为 1。
    • vector<int> v4{10, 1};
      解释:v4 被列表初始化,列表中有两个元素,分别是 10 和 1,因此 v4 包含两个元素,值分别为 10 和 1。

因此,在使用花括号时,编译器会尽可能将花括号中的值解释为元素初始值的列表,而不是用来构造 vector 对象的参数。

注意:
如果希望利用初始值来构造 vector 的元素数量及统一初始值,必须使用圆括号。例如:

vector<int> v3(10, 1);  // 正确,v3 有 10 个元素,每个元素为 1

而使用花括号:

vector<int> v4{10, 1};  // v4 有 2 个元素,分别为 10 和 1

4. 值初始化与直接初始化

当只提供 vector 对象中元素的数量而不指定初始值时,vector 会对每个元素执行值初始化。

  • 对于内置类型(如 int),值初始化将每个元素初始化为 0。
  • 对于类类型(如 string),调用默认构造函数来初始化对象(通常得到空字符串)。

例如:

vector<int> ivec(10);       // 10 个 int 元素,每个初始化为 0
vector<string> svec(10);    // 10 个 string 元素,每个默认初始化为空字符串

特殊限制:

  • 如果 vector 的元素类型不支持默认初始化(例如某些类要求必须明确提供初始值),那么仅提供元素数量将无法完成初始化。
  • 当只提供数量时,只能使用直接初始化的形式,而不能使用拷贝初始化。例如:
    vector<int> vi = 10; // 错误:拷贝初始化不能仅用一个整数来表示 vector 的大小
    
    正确做法应是:
    vector<int> vi(10);
    

5. 小结

  • 默认初始化:
    vector<T> v; 创建一个空的 vector,随后可以通过 push_back 等操作动态添加元素。

  • 拷贝初始化:
    vector<T> v2 = v1;vector<T> v2(v1); 都是创建一个新 vector,其内容为已有 vector 的副本。

  • 直接初始化指定初始值:
    vector<T> v3(n, val); 创建一个包含 n 个元素的 vector,每个元素初始化为 val。

  • 列表初始化:
    使用花括号形式初始化,例如 vector<T> v5{a, b, c};,此时 v5 的元素个数为花括号中的初始值个数,且每个元素分别初始化为对应的值。

  • 圆括号与花括号的区别:
    同样的数值在圆括号和花括号中可能有不同含义。例如,vector<int> v1(10); 表示 10 个元素(每个为 0),而 vector<int> v2{10}; 表示只有一个元素,其值为 10;vector<int> v3(10,1); 表示 10 个元素,每个为 1,而 vector<int> v4{10,1}; 表示两个元素,分别为 10 和 1。

  • 值初始化:
    当只提供元素数量时,元素根据其类型自动值初始化。

通过全面理解 vector 对象的各种初始化方式,你可以更灵活地构建和管理容器,确保代码既清晰又符合预期。对于复杂的初始化需求,选择合适的初始化方式可以大大提高代码的可读性和维护性。

参考资料

  • cppreference.com 关于 std::vector 构造函数的详细说明
  • 各大 C++ 编码规范(如 Google C++ Style Guide)中对容器初始化的建议

希望这篇全面的讲解能够帮助你深入理解如何定义和初始化 vector 对象,以及圆括号与花括号在初始化时的微妙区别,从而为后续使用 vector 提供坚实的基础。

相关文章:

  • TypeScript学习第十六篇 - interface和type的区别?
  • 【在线OJ项目测试报告】
  • 第十章Python语言高阶加强-SQL(数据库)
  • windows AndroidStudio上传maven中央仓库
  • MySQL约束详解:从入门到精通
  • java.util.Collections中常用api
  • Systemd安全加密备份系统与智能通知
  • 深信服Python开发面经及参考答案(110道题)
  • 第十四届蓝桥杯省赛真题解析(含C++详细源码)
  • 常见框架漏洞(五)----中间件IIS6
  • 罗米:《俄罗斯博物馆之旅》
  • 【C++11】异常
  • C语言学习笔记-9
  • Redis-x64-3.2.100.msi : Windows 安装包(MSI 格式)安装步骤
  • MessageQueue --- RabbitMQ可靠传输
  • [项目总结] 在线OJ刷题系统项目技术应用(下)
  • 同花顺客户端公司财报抓取分析
  • 【AI Infra】【RLHF框架】四、VeRL中PPO、GRPO、REINFORCE++、RLOO实现源码解析
  • Spring 怎么解决循环依赖问题?
  • 室内指路机器人是否支持与第三方软件对接?
  • 品牌建设 凝心/360优化大师历史版本
  • 专业培训/seo综合查询站长工具关键词
  • 网站开发综合设计报告/短链接购买
  • 做设计不进设计公司网站/营销托管全网营销推广
  • 请人做阿里巴巴网站需要注意/今天的新闻有哪些
  • 南昌营销型网站建设/交换友链要注意什么