我有这段代码:
#include <set>
int main() {
int array[] = { 0 };
std::set<int> stdset(&array[1], &array[1]);
}
获取超出最后一个数组元素的元素的地址并将其转换为迭代器。基本上与std::vector::end()
的作用相同。
这样做是合法的:
std::vector<int> vec;
std::set<int> stdset(vec.end(), vec.end());
因为“last”迭代器是一个非包容性限制。
对原始数组执行与第一个代码段相同的操作是否合法?
答案 0 :(得分:1)
你可以在C ++中获取任何数组的一个接一个地址。
你不能dereferrence并使用结果,但你可以将它与同一阵列的其他指针和同一阵列的其他一对一的指针进行比较。
您在OP中所做的是定义的行为,并代表一个空的范围。
答案 1 :(得分:1)
不涉及转换。指针支持与随机访问迭代器(一元*
运算符,++
和+
运算符等)相同的操作,因此可以用作迭代器。采用迭代器的标准库函数是在迭代器的类型上进行模板化的,因此它们将获取指针而不将其转换为任何东西。
这一点,以及指向数组末尾的指针有效的事实(只要你没有取消引用它),就意味着你的代码是正确的。
答案 2 :(得分:1)
你没有转换任何东西:指针是有效的迭代器而不是矢量。
获取一个指向数组末尾的元素的指针是合法的,但取消引用这样的指针是不合法的。
ANSI C,第5.7段第5段:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)指向分别为数组对象的第i + n和第i-n个元素,只要它们存在。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为是未定的。
我在网上的C ++标准引用中没有找到对此的引用,我没有C ++标准的副本,所以我无法证明它仍然是关于C ++的最新版本,但它可能是。
TL; DR:您的代码是合法的。
答案 3 :(得分:-1)
说实话,我根据任何规格都不知道你问题的答案。然而,我在您的方法中看到的问题是,您正在将实现与您正在使用的库中的实现细节联系起来。
如果将实现绑定到您使用的库所公开的接口,那么如果这些库的实现发生更改,则消耗代码的可能性就会降低。在这种特殊情况下,这可能不是很相关,因为数组的内存布局在不久的将来不太可能改变,但如果确实如此,运行时库开发人员也可能相应地改变迭代函数的实现,所以如果如果使用公开的函数,您的代码应该按预期继续工作。但是,如果您的代码依赖于库的实现细节,那么您可能需要完成所有案例使用并相应地更改它们。
编辑:
对不起,我不认为我表达得很清楚;我不是在谈论你的代码,而是谈论你的方法。封装的一个好处是它允许编写代码组件,每个代码组件都是自己的任务,然后通过组合多个代码组件提供的功能来完成应用程序。具有多个抽象级别使我们能够设计较高级别而无需担心较低级别的微小细节。
如果构成整个应用程序的不同组件与彼此的实现细节保持隔离,则组件可以轻松升级而不会破坏兼容性,只要组件保持其最小接口并且其实现行为正确即可。如果不同组件彼此相互依赖,则升级变得更加困难,因为需要根据所涉及组件的内部结构进行更改;在较低级别的组件中看似无害的修改(比如在两个较旧的组件之间插入一个新的成员变量)可能会在完全不相关的代码片段中“巧妙地”依赖于组件的内部结构而产生完全不可预见的后果。
在编程领域,您可以使用您找到的任何资源将输入转换为输出,但这并不意味着所有可能性都具有相同的含义。如果您担心执行时间并且调用函数的开销是不可接受的,那么您可以通过完全跳过面向对象的方法并通过索引迭代数组来获得一些额外的周期。如果执行时间不是那么关键,它允许在接口上调用公共方法,那么通过使用它,你将获得更小的升级噩梦。