You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

聚合初始化时类内成员初始化顺序:标准是否规定i晚于v初始化?

聚合初始化中类内成员初始化的执行顺序问题

先看这段代码:

#include <iostream>
#include <print>
#include <span>
#include <vector>

struct Entry {
  std::vector<char> v;
  std::vector<char>::iterator i = v.begin();
};

int main() {
  std::vector<char> v{'a', 'b', 'c', 'd', 'e'};
  Entry e{.v = std::move(v)};
  std::print(std::cout, "{}", std::span(e.i, e.v.end()));
}

这段代码运行后会输出['a', 'b', 'c', 'd', 'e']。有人可能误以为Entry e{.v = std::move(v)};的逻辑类似先默认构造e再给e.v赋值,会导致e.i失效,但实际并非如此——它的执行逻辑更接近先初始化e.v,再用初始化后的e.v来初始化e.i。

核心问题解答

是的,聚合初始化过程中,类内初始化语句.i = v.begin()必然在v完成初始化之后执行,C++标准对此有明确规定。

具体规则说明

根据C标准(以C20为例,对应条款§9.4.2 [dcl.init.aggr]):

  • 聚合初始化时,成员的初始化顺序严格遵循它们在类定义中的声明顺序,完全不受初始化列表中指定的顺序影响;
  • 对于初始化列表中没有指定初始化的成员,会使用其类内初始化器完成初始化,这一步会在所有前面声明的成员都完成初始化后执行。

对于Entry结构体,v的声明早于i:

  1. 首先执行初始化列表中的.v = std::move(v),完成e.v的移动构造初始化;
  2. 接着执行i的类内初始化器v.begin()——此时v已经是完全初始化后的有效容器,因此i会指向e.v的起始位置,是有效的迭代器。

这和“默认构造Entry后再给v赋值”的场景完全不同:后者是先默认构造v(空容器),此时i会指向空容器的起始迭代器;之后给v赋值会导致容器重新分配内存,原来的迭代器i失效。而聚合初始化是直接按声明顺序初始化成员,不会出现迭代器失效的问题。

内容的提问来源于stack exchange,提问作者3CEZVQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:54:50