可以将两个相同类型的连续数组视为一个数组吗?

Can two consecutive arrays of the same type be treated as one?

本文关键字:数组 连续 一个 同类型 两个      更新时间:2023-10-16

考虑下面的代码:

struct S {
int a[2] = {1, 1};
int b[3] = {2, 2 ,2};
};
int main() {
S s;
for (auto *p = std::begin(s.a); p != std::end(s.a); p++)
std::cout << *p  << std::endl;
for (auto *p = std::begin(s.b); p != std::end(s.b); p++)
std::cout << *p  << std::endl;

return 0;
}

我可以像这样重写它(并且仍然有相同的结果(吗?

struct S {
int a[2] = {1, 1};
int b[3] = {2, 2 ,2};
};
int main() {
S s;
for (auto *p = std::begin(s.a); p != std::end(s.b); p++)
std::cout << *p  << std::endl;

return 0;
}

此代码中的S结构是 StandardLayout,因此可以保证b的地址高于a。第二种方法是安全的还是存在某种 UB?

如果a只是一个int(而不是数组(怎么办?我可以执行以下操作吗?

for (auto *p = &s.a; p != std::end(s.b); p++)
std::cout << *p  << std::endl;

对于标准布局类型,有一个注释:

因此,在实现插入的标准布局结构对象中可能存在未命名的填充,但不在其开头,这是实现适当对齐所必需的。

因此,成员ab之间可能会有填充。

即使没有填充,std::begin(b)std::end(a)也会简单地返回指向基础数组的指针。未指定比较指针a + 2b的结果。此外,简单地计算a + 3是未定义的,因此您无法像尝试使用指针那样执行此操作。

要获得所需的效果,您可以编写一个自定义迭代器接口,该接口在内部管理指向不同对象的指针。或者你可以只使用 range-v3 库,如下所示:

for(auto i : ranges::views::concat(s.a, s.b))
std::cout << i;

如果您定义自定义迭代器,则可以完成此操作

int main(int, char**)
{
class S {
private:
int a[2] = { 1, 2 };
std::string someString;
int b[3] = { 3, 4, 5 };
int doNotInclude[3] = { 100, 101, 102 }; // let's do not include this array for our output loop for example
int c[3] = { 6, 7, 8 };
public:
class iterator {
private:
int* curr;
S* sOuter;
public:
iterator(S* Outer, int* р) :sOuter{ Outer }, curr(р) {}
int& operator* () { return *curr; };
bool operator==(const iterator& b) const { return curr == b.curr; };
bool operator!=(const iterator& b) const { return curr != b.curr; }
iterator& operator++() {
if (std::end(this->sOuter->a) == curr + 1) {
curr = std::begin(this->sOuter->b);
}
else if (std::end(this->sOuter->b) == curr + 1) {
curr = std::begin(this->sOuter->c);
}
else {
++curr;
}
return *this;
}
};
iterator begin() { return iterator(this, std::begin(a)); };
iterator end() { return iterator(this, std::end(c)); };
};
S s;
for (auto& v : s) {
std::cout << v << std::endl;
}
return 0;
}
1
2
3
4
5
6
7
8