我有一个全局状态的数组。这是在嵌入式/微控制器环境中运行,而不是在大型应用程序中我可能更关心全局状态。
如何声明数组,使其成员无法更改,但我仍然可以更新副本,并且在需要时仍然完全覆盖全局数组?
我有兴趣使用不可变数组,以便能够在从突变函数返回时快速检查它是否已更改。也就是说,如果内存地址发生了变化,那么我就知道它被复制和更新了。
如果已经更新了,那么我想用更新的版本覆盖原来的全局数组。
但是,我想保护数组的各个值不被 main() 中意外覆盖,或者防止全局数组被访问并直接更新。也许我有点偏执,但为了这个问题,我们可以说这是一个合理的担忧。
唯一可能的更新应通过副本/地址更新来完成。
这个版本可以用,但是全局数组可以访问并直接更新:
#include <array>
#include <iostream>
std::array<int, 3> arr = {1, 2, 3}; // global array
std::array<int, 3> const * mutate(std::array<int, 3> const * ptr) {
// (*ptr)[2] = 9; // I like how this is prevented by const
// return ptr; // uncomment to test no mutation
// mutation via copy, retain new array on the heap
std::array<int, 3> * ret = new std::array<int, 3>;
std::copy((*ptr).begin(), (*ptr).end(), (*ret).begin());
(*ret)[0] = 9;
return ret;
}
int main() {
std::array<int, 3> const * retPtr = mutate(&arr);
if (retPtr == &arr) {
std::cout << "pointers are the same\n";
} else {
std::cout << "pointers are different\n";
arr = (*retPtr);
// do expensive things here with the new state
}
delete[] retPtr;
for (int val : arr) {
std::cout << val;
std::cout << "\n";
}
return 0;
}
首先我尝试将数组声明为
std::array<int, 3> const
。这使我无法完全覆盖数组。
std::array<int, 3> const arr = {1, 2, 3};
...
arr = (*retPtr); // Compilation error: no viable overloaded '='
然后我尝试将其声明为
std::array<int const, 3>
,但这使我无法在突变函数中对副本进行突变。
std::array<int const, 3> arr = {1, 2, 3};
std::array<int const, 3> * mutate(std::array<int const, 3> * ptr) {
std::array<int const, 3> * ret = new std::array<int const, 3> {0,0,0};
std::copy((*ptr).begin(), (*ptr).end(), (*ret).begin());
// Compilation error: cannot assign to return value because function 'operator[]'
// returns a const value
(*ret)[0] = 9;
return ret;
}
预先感谢您提供的任何帮助!
假设您使用的是 c++20 或更高版本,现在这是可行的。 基本生活的改变使得替换对象成为可能,只要被替换的对象可以透明地替换。这限制了您不能更改数组的长度或其元素类型,因为它们会更改对象类型。
#include <iostream>
#include <array>
#include <memory>
std::array< const int, 3> a{ 1,2,3 };
void mutate()
{
std::destroy_at(&a); // call destructor. not needed unless array elements have destructors
std::construct_at(&a, std::array<const int, 3> {2, 3, 4});
}
int main()
{
mutate();
std::cout << a[0] << '\n';
}