当应用于不相关的指针时,std::less 如何比 < 更安全?
How can std::less be safer than < when applied to unrelated pointers?
我发现我应该使用 std::less
来比较我的对象,以便能够比较不相关的指针(来自不同的序列),因为仅使用关系运算符 <
会产生 UB 如果用在那些不相关的指针上。
所以为了练习,我实现了我的 compare
函数:
#include <iostream>
using namespace std;
#include <functional>
template <class T>
constexpr int compare(T const& x, T const& y)
{
if(std::less<T>()(x, y))
return -1;
if(std::less<T>()(y, x))
return 1;
return 0;
}
int main()
{
std::cout << compare(std::string("Hello"), std::string("hello")) << std::endl;
std::cout << compare(std::string("hello"), std::string("Hello")) << std::endl;
std::cout << compare(std::string("hello"), std::string("hello")) << std::endl;
std::cout << compare(-7, 1) << std::endl;
int* p1{new int(10)};
int* p2{new int{4}};
std::cout << compare(p2, p1) << std::endl;
std::cout << "\ndone!\n";
}
输出:
-1
1
0
-1
1
为什么我不应该在那种情况下直接使用 <
?
std::less
怎么可能比 <
更安全?我的意思是内部结构。谢谢!
How can be std::less
safer than <
?
因为标准是这么说的。
I mean the internals.
在所有 x64 和大多数现代架构上,std::less::operator()
只是对 built-in 运算符 <
的简单包装,或者将指针转换为 uinptr_t
然后进行比较。
C++ 旨在用于各种硬件架构,因此可能存在一些架构(历史?、古老?、怪异?),其中并非所有数据地址都(容易)具有可比性。在这些架构上,运算符 <
不起作用,而需要 std::less
来实现工作方式。
附带说明一下,您没有在示例中比较指针
should I use std::less
instead of <
对于指向(可能)不同对象或在不同数组中的指针,是的,否则,如果您在这种情况下使用 <
,则您有未定义的行为。没有别的。 std::less
在您需要为其他一些函数提供比较函数时最有用(例如 std::sort
)。
例如:
int a{}, b{}
int* p_a = &a;
int* p_aa = &a;
int* p_b = &b;
p_a < p_b; // technically Undefined Behavior, use std::less instead:
std::less<>{}(p_a, p_b);
p_a < p_a; // ok
p_a < p_aa; // ok
int arr1[10]{}
int* p1_1 = &arr1[0];
int* p1_2 = &arr1[5];
int arr2[10]{};
int* p2_1 = &arr2[0];
int* p2_2 = &arr2[5];
p1_1 < p2_1; // technically Undefined Behavior, use std::less instead:
std::less<>{}(p_1_1, p_2_1);
p1_1 < p1_2; // ok
p2_1 < p2_2; // ok
char str[] = "hello";
char* str_end = str + strlen(str);
for (char* p = str; p < str_end; ++p) // ok
// ...
其他使用<
int a{}, b{};
a < b; // ok
std::string s1{}, s2{};
s1 < s2; // ok
我发现我应该使用 std::less
来比较我的对象,以便能够比较不相关的指针(来自不同的序列),因为仅使用关系运算符 <
会产生 UB 如果用在那些不相关的指针上。
所以为了练习,我实现了我的
compare
函数:#include <iostream> using namespace std; #include <functional> template <class T> constexpr int compare(T const& x, T const& y) { if(std::less<T>()(x, y)) return -1; if(std::less<T>()(y, x)) return 1; return 0; } int main() { std::cout << compare(std::string("Hello"), std::string("hello")) << std::endl; std::cout << compare(std::string("hello"), std::string("Hello")) << std::endl; std::cout << compare(std::string("hello"), std::string("hello")) << std::endl; std::cout << compare(-7, 1) << std::endl; int* p1{new int(10)}; int* p2{new int{4}}; std::cout << compare(p2, p1) << std::endl; std::cout << "\ndone!\n"; }
输出:
-1
1
0
-1
1
为什么我不应该在那种情况下直接使用
<
?std::less
怎么可能比<
更安全?我的意思是内部结构。谢谢!
How can be
std::less
safer than<
?
因为标准是这么说的。
I mean the internals.
在所有 x64 和大多数现代架构上,std::less::operator()
只是对 built-in 运算符 <
的简单包装,或者将指针转换为 uinptr_t
然后进行比较。
C++ 旨在用于各种硬件架构,因此可能存在一些架构(历史?、古老?、怪异?),其中并非所有数据地址都(容易)具有可比性。在这些架构上,运算符 <
不起作用,而需要 std::less
来实现工作方式。
附带说明一下,您没有在示例中比较指针
should I use
std::less
instead of<
对于指向(可能)不同对象或在不同数组中的指针,是的,否则,如果您在这种情况下使用 <
,则您有未定义的行为。没有别的。 std::less
在您需要为其他一些函数提供比较函数时最有用(例如 std::sort
)。
例如:
int a{}, b{}
int* p_a = &a;
int* p_aa = &a;
int* p_b = &b;
p_a < p_b; // technically Undefined Behavior, use std::less instead:
std::less<>{}(p_a, p_b);
p_a < p_a; // ok
p_a < p_aa; // ok
int arr1[10]{}
int* p1_1 = &arr1[0];
int* p1_2 = &arr1[5];
int arr2[10]{};
int* p2_1 = &arr2[0];
int* p2_2 = &arr2[5];
p1_1 < p2_1; // technically Undefined Behavior, use std::less instead:
std::less<>{}(p_1_1, p_2_1);
p1_1 < p1_2; // ok
p2_1 < p2_2; // ok
char str[] = "hello";
char* str_end = str + strlen(str);
for (char* p = str; p < str_end; ++p) // ok
// ...
其他使用<
int a{}, b{};
a < b; // ok
std::string s1{}, s2{};
s1 < s2; // ok