自定义构造函数中fenwick_tree结构体成员是否被构造两次?
问题分析与解答
相关代码
PhiBlock 结构体定义
struct PhiBlock { int64_t bsize; // block size vector<int64_t> ind; // 0/1 to track [pmin(y) > pb] fenwick_tree phi_sum; // partial sums PhiBlock (int64_t bsize, int64_t a): phi_sum(ind) { this->bsize = bsize; ind.resize(bsize, 1); phi_sum = fenwick_tree(ind); } // ... };
fenwick_tree 结构体定义
struct fenwick_tree { size_t len; // 0-based len std::vector<int64_t> t; // 1-based tree, indexes [1:len] fenwick_tree(std::vector<int64_t> const &a) { len = a.size(); t.assign(len + 1, 0); for (size_t i = 0; i < len; ++i) add_to(i, a[i]); } // ... };
疑问与解答
1. 对初始化流程的理解是否正确?
你的理解完全正确:
- 由于
fenwick_tree没有默认构造函数,必须在成员初始化列表中显式初始化phi_sum,此时ind是默认构造的空vector,因此第一次构造的phi_sum是基于空容器的实例; - 进入构造函数体后,
ind被resize为指定大小并填充1; - 最后通过
fenwick_tree(ind)创建临时对象,再赋值给phi_sum,完成第二次构造(临时对象)+ 赋值操作。
2. phi_sum 是否必须被构造两次?
在当前代码结构下,是的。成员初始化阶段必须完成phi_sum的构造(无默认构造函数时编译器无法自动初始化),但此时ind还未被初始化到目标状态,只能先基于空ind构造一次,后续再通过赋值替换。
不过可以通过调整代码避免两次构造:将ind的初始化移到成员初始化列表中,直接用正确状态的ind构造phi_sum,示例如下:
PhiBlock (int64_t bsize, int64_t a): bsize(bsize), ind(bsize, 1), phi_sum(ind) {}
这样只需构造一次phi_sum,完全避免后续赋值操作。
3. 给fenwick_tree添加默认构造函数后,是否无需成员初始化列表?
是的。如果给fenwick_tree添加空操作的默认构造函数(比如初始化空vector、设置len=0),编译器会自动在成员初始化阶段调用默认构造函数初始化phi_sum,此时无需在初始化列表中显式声明phi_sum的初始化,后续可在构造函数体中对phi_sum进行赋值或重新初始化。
关于优化的补充
未开启-O2时,确实能看到两次fenwick_tree构造操作;开启-O2后,编译器可能会优化掉后续的赋值操作(比如直接修改第一次构造的phi_sum实例,而非创建临时对象再赋值),但这属于编译器的优化行为,不能依赖它保证代码正确性或性能,建议从代码结构上避免不必要的构造。
内容的提问来源于stack exchange,提问作者qwr
相关产品推荐
相关产品推荐

