为什么C++常量模板化向量在使用之前没有初始化?
Why isn't that C++ const templated vector initialised before being used?
更新:问题是为什么下面的代码(MWE(按原样工作,而不是像我期望的那样工作。
为了个人方便,我创建了以下模板化向量:
// shorthand for loops, etc.
template <size_t N>
const vector<size_t> range = []() {
vector<size_t> res(N);
for (size_t i = 0; i < N; i++) res[i] = i;
cout << "Created range<" << N << ">: [";
for (auto x: res) cout << x << ' ';
cout << ']' << endl;
return res;
}();
因此,我可以进一步编写更多简洁的循环,如下所示:
for (auto i : range<42>) do_something(i);
但是,我意识到(经过一些调试(似乎不能保证在使用前初始化所有必需的range<N>
实例!这是相当违反直觉的,所以我认为如果我做错了什么。
更准确地说,我有以下MWE:
#include <bits/stdc++.h>
using namespace std;
template <size_t N>
const vector<size_t> range = []() {
cout << "Initialising range<" << N << ">" << endl;
vector<size_t> result(N);
for (size_t i = 0; i < N; i++) result[i] = i;
return result;
}();
template <size_t K>
class Data {
private:
size_t m_code;
public:
size_t get_code() const { return m_code; }
constexpr static size_t cardinality = K + 1;
explicit Data(size_t code);
const static vector<Data> elems;
};
template <size_t K>
const vector<Data<K>> Data<K>::elems = []() {
cout << "Creating Data elements for K=" << K << endl;
vector<Data<K>> xs;
for (size_t i : range<Data<K>::cardinality>) xs.push_back(Data<K>(i));
return xs;
}();
template <size_t K>
Data<K>::Data(size_t code) {
m_code = code;
cout << "At the moment, range<" << K << "> is [";
for (auto k : range<K>)
cout << k << ' '; // <<< Shouldn't range<K> be already initialised here?..
cout << "] (len=" << range<K>.size() << ")" << endl;
}
int main() {
cout << ">>> Inside main()" << endl;
constexpr size_t K = 2;
cout << "Data elements:" << endl;
for (const auto &X : Data<K>::elems) {
cout << "Element Data(" << X.get_code() << ")" << endl;
}
cout << "Now, range<" << K << "> is [";
for (auto k : range<K>) cout << k << ' ';
cout << "] (len=" << range<K>.size() << ")" << endl;
}
这将生成以下输出:
Initialising range<3>
Creating Data elements for K=2
At the moment, range<2> is [] (len=0)
At the moment, range<2> is [] (len=0)
At the moment, range<2> is [] (len=0)
Initialising range<2>
>>> Inside main()
Data elements:
Element Data(0)
Element Data(1)
Element Data(2)
Now, range<2> is [0 1 ] (len=2)
我真的不明白为什么它会按原样工作。我的意思是,我希望在使用之前初始化一个const
向量(或任何向量!(,因此每当我在代码中使用它时range<2>
长度为二。
由(非显式(模板专用化产生的非本地静态存储持续时间变量的动态初始化是无序的,即不确定地排序,这意味着初始化发生的顺序是未指定的。它既不考虑变量之间的依赖关系,也不考虑定义的顺序或实例化的顺序。
因此你的程序有未定义的行为,因为Data<2>::elems
,从main
中的使用实例化,具有无序的动态初始化,并使用range<2>
和range<3>
,两者都有无序的动态初始化。由于未指定是先初始化前者还是后者,因此您可能会在初始化开始之前访问range<2>
或range<3>
,从而导致未定义的行为。
这可以通过使用std::array
而不是std::vector
forrange
及其初始值设定项(并删除初始值设定项中的cout
语句(来解决,以便初始值设定项成为常量表达式。然后range<K>
将没有动态初始化,而是常量初始化,它总是在任何动态初始化之前执行,即在Data<K>::elems
使用它之前。
此外,还应将range
声明为constexpr
,以确保初始值设定项确实是一个常量表达式。否则,您可能仍会在没有警告的情况下获得动态初始化和未定义的行为,例如,当您所做的更改意外导致初始值设定项不再是常量表达式时。
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- 初始化常量字符* 数组
- 为什么MSVC14允许声明指向动态未初始化常量对象的指针
- C++初始化常量
- 在可变参数构造函数中初始化常量数组
- 使用数字初始化常量引用
- 如何在不初始化常量的情况下声明数组?
- 初始化常量静态 std::map unique_ptr作为值
- 为什么您可以初始化常量引用,但不能初始化来自右值的非常量引用
- 类中的初始化常量
- 如何初始化常量 CLSID
- 在类中初始化常量数组
- 在声明C++之后初始化常量变量
- C++初始化:常量全局与静态类成员的顺序
- 在头文件中声明并初始化常量
- 恒常性添加无效?错误:无法使用字符**初始化常量字符**
- 为什么我能够在构造函数中初始化常量
- 通过指针初始化常量矩阵<双精度,0,80>(来自 Dlib)
- C++构造函数:初始化常量引用时出现垃圾
- 用自身初始化C++常量变量