gpt4 book ai didi

c++ - 为什么 C++ const 模板化 vector 在使用之前没有初始化?

转载 作者:行者123 更新时间:2023-12-02 11:16:44 25 4
gpt4 key购买 nike

更新:问题是为什么下面的代码(MWE)按原样工作,而不是按照我的预期工作。

为了个人方便,我创建了以下模板化 vector 常量:

// 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 vector (或任何 vector !)在使用之前进行初始化,因此 range<2>每当我在代码中使用它时,长度都为 2。

最佳答案

由(非显式)模板特化产生的非本地静态存储持续时间变量的动态初始化是无序的,即不确定地排序,这意味着初始化发生的顺序是未指定的。它不考虑变量之间的依赖关系、定义顺序或实例化顺序。

因此你的程序有未定义的行为,因为 Data<2>::elems ,从 main 中的使用实例化,具有无序动态初始化并使用 range<2>range<3> ,两者都具有无序动态初始化。由于未指定是先初始化还是先初始化,因此有可能访问range<2>。或range<3>在初始化开始之前,导致未定义的行为。

这可以通过使用 std::array 来解决而不是std::vector对于 range并在其初始值设定项中(并删除初始值设定项中的 cout 语句),以便初始值设定项成为常量表达式。然后range<K>不会有动态初始化,而是常量初始化,它总是在任何动态初始化之前执行,即在Data<K>::elems之前执行。会使用它。

此外,您还应该声明 rangeconstexpr确保初始化程序确实是一个常量表达式。否则,您可能仍然会在没有警告的情况下获得动态初始化和未定义的行为,例如,当您进行更改时意外地导致初始化程序不再是常量表达式。

关于c++ - 为什么 C++ const 模板化 vector 在使用之前没有初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60235315/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com