我缺乏语言的行业经验。但是在业余时间我遇到过几个需要比较指针的地方,最好是标准定义的行为。
第一种情况,如果我决定在我的应用程序中使用有序二叉树作为容器(而不是哈希表)并且我希望相等是对象的标识(即相等意味着相同的实例),那么我发现没有可移植的方式这样做。
其次,如果我想测试“完整对象”和它们的子对象之间的包含关系,我似乎再没有可移植的方法。那就是如果我有两个void *指针“p”和“q”,并且我有“q”所指向的对象的大小,我看不出来测试“p”是否是非静态成员变量“q”与否。我没有从标准中的第5.9段(“关系运营商”)中找到鼓励。例如,后一种情况出现在此提升论坛post的垃圾收集器中。我喜欢这个一般的想法并开始探索它,但是某些部分似乎以不可移植的方式使用指针和分配语义。
这就是我想知道如何从以下代码中使contains
函数可移植:
#include <stddef.h>
#include <assert.h>
struct A {
int x;
} a;
struct B {
int y;
} b;
bool contains(const void *outer, size_t size, const void *inner)
{
return (outer <= inner) &&
(inner < static_cast<const char *>(outer) + size);
}
int main()
{
assert(contains(&a, sizeof(a), &a.x));
assert(contains(&b, sizeof(b), &b.y));
assert(!contains(&a, sizeof(a), &b.y));
assert(!contains(&b, sizeof(b), &a.x));
}
谢谢和最诚挚的问候。
PS:
好的,在再次查阅标准之后,我看到它明确指出,正如GMan在他的回答中所说,less
和less_equal
之类的函子提供了指针的总排序。我认为这也暗示了排序与内置比较运算符<
和<=
一致,但这一点可以更迂腐地解决。当指针不指向同一数组或同一对象的子对象时,内置运算符是不可预测的。我的意思是,这个总顺序中的独特性测试是什么 - 指针的二进制表示?例如,如果没有以明确定义的方式与内置运算符进行比较,那么void*
指针的总顺序中的不相同是什么意思?
对于具有相同访问控制的成员变量,标准在内存中定义它们的顺序,即通过指针比较观察时。它是对象类型定义中的外观顺序。从内置比较运算符的角度来看,第一个成员变量的地址最小,最后一个成员变量的地址最大。此外,在关于类型的部分中,陈述了“平凡可复制类型”的对象将在&
运算符的值和以下sizeof
字符之间的范围内布置在存储器中。现在让我们假设仿函数提供了指向不同对象的指针的总顺序。这是不是意味着,即使无意中,标准意味着上面代码段的行为,如果使用仿函数而不是contains
函数中的内置运算符?
只是想明确一点 - 如果标准有遗漏,或者只是需要澄清,或者它为指针比较的实现留下了灵活性。
答案 0 :(得分:6)
我不太确定你要求的是什么(例如,你到底想要完成什么?),但我认为这是你想知道的:
greater
中定义的关系仿函数greater_equal
,less
,less_equal
和<functional>
会产生任何指针类型的总排序,即使构建了在关系运算符中没有。
那是:
#include <functional>
#include <iostream>
int main()
{
int i, *j = &i;
int k, *l = &k;
std::cout << std::boolalpha << std::less<int*>()(j, l) << std::endl;
}
定义明确。 (注意输出是实现定义的,但 保证总排序。)
关联容器谓词默认为std::less
,因此可以将指针用作键。