C++ memcmp与多重相等比较 预条件< /强>:考虑此类类或结构 t>代码>,对于两个对象 < > b>代码>类型 t>代码> memcmp(&a, &b, sizeof(T)) == 0
产生的结果与C++ memcmp与多重相等比较 预条件< /强>:考虑此类类或结构 t>代码>,对于两个对象 < > b>代码>类型 t>代码> memcmp(&a, &b, sizeof(T)) == 0,c++,memcmp,C++,Memcmp,产生的结果与 a.member1 == b.member1 && a.member2 == b.member2 && ... (memberN是T的非静态成员变量) 问题:什么时候应该使用memcmp来比较a和b是否相等,什么时候应该使用链接的=s 下面是一个简单的例子: struct vector { int x, y; }; 要重载向量的运算符==,有两种可能性(如果它们保证给出相同的结果): 或 现在,如果要将新成员添加到vector,例如z
a.member1 == b.member1 && a.member2 == b.member2 && ...
(memberN
是T
的非静态成员变量)
问题:什么时候应该使用memcmp
来比较a
和b
是否相等,什么时候应该使用链接的=
s
下面是一个简单的例子:
struct vector
{
int x, y;
};
要重载向量的运算符==
,有两种可能性(如果它们保证给出相同的结果):
或
现在,如果要将新成员添加到
vector
,例如z
组件:
- 如果使用
s实现=
,则必须对其进行修改运算符==
- 如果改为使用
,memcmp
,则根本不需要修改operator==
但我认为使用chained
==
s可以传达更清晰的含义。虽然对于拥有众多成员的大型T
,memcmp
更具吸引力。此外,与=
s相比,使用memcmp
是否有性能改进?如你所说,如果你选择了这样的类型,那么这两个解决方案会产生相同的结果(大概是,你没有间接数据,对齐/填充都是一样的),那么显然你可以使用你喜欢的任何解决方案。
需要考虑的事项:
T
是一样的,但它们是一样的吗?真的吗?在所有系统上?您的memcmp
方法是否可移植?可能不会李>
memcmp
的使用进行充分的说明,那么您的程序很可能会崩溃-因此您使其变得脆弱李>
=
;当然,对于每一个不符合您的前提条件的T
,您都必须这样做;除非这是对<>代码>代码>的精心优化,否则你可以考虑在程序中坚持单一方法;李>
==
中漏掉一个成员,尤其是当您的成员列表不断增加时如果两种解决方案都是正确的,则选择可读性更强的解决方案。我认为,对于C++程序员来说,
std::tie
而不是链接:
bool operator==(const vector &lhs, const vector &rhs)
{ return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y); }
如果有,仅当结构是POD且安全地
memcmp
可比较(甚至不是所有数字类型都是…)时,结果是相同的,问题在于可读性和性能
可读性?我认为这是一个基于观点的问题,但我更喜欢操作符==
性能?操作员==
是一个短路操作员。在这里,您可以对程序进行更多的控制,因为您可以对比较序列进行重新排序
虽然a==b&&c==d
和c==d&&a==b
在算法逻辑方面是等价的(结果是一样的),但它们在生成的程序集、“背景逻辑”和可能的性能方面是不等价的
如果你能看到一些要点,你可以影响你的计划
例如:
- 如果两个语句产生false的可能性大致相同,那么您需要先使用更便宜的语句,以尽可能跳过更复杂的比较
- 如果这两个语句的复杂程度大致相同,并且您事先知道
比c==d
更容易出错,那么您应该首先比较a==b
和c
d
operator==
可以根据问题调整比较顺序,而memcmp
不提供这种自由
PS:您可能希望对其进行测量,但对于一个包含3个成员的小型结构,MS VS 2013会为memcmp
情况生成稍微复杂的程序集。在这种情况下,我希望操作符==
解决方案具有更高的性能(如果影响可以测量的话)
-/伊迪丝-
注意:即使POD结构成员也可以重载运算符==
考虑:
#include <iostream>
#include <iomanip>
struct A { int * p; };
bool operator== (A const &a, A const &b) { return *(a.p) == *(b.p); }
struct B { A m; };
bool operator== (B const &a, B const &b) { return a.m == b.m; }
int main()
{
int a(1), b(1);
B x, y;
x.m.p = &a;
y.m.p = &b;
std::cout << std::boolalpha;
std::cout << (memcmp(&x, &y, sizeof(B)) == 0) << "\n";
std::cout << (x == y) << "\n";
return 0;
}
<>即使所有成员都是基本类型,我更喜欢<代码>运算符==/COD>并将其留给编译器来考虑将比较优化到它认为是优选的任何程序集。 < P>你强加了一个非常强的条件,即没有填充。(我假设不是在类成员之间,也不是在这些成员内部)。我猜想您也打算排除任何“隐藏的”来自类的内务管理数据。此外,问题本身意味着我们总是比较完全相同类型的对象。在如此强大的条件下,可能无法想出一个反例,使基于
memcmp
的比较不同于=
的比较
出于性能方面的原因,是否值得使用
memcmp
。。如果你真的有充分的理由积极优化一些关键的代码,并且分析表明从==
切换到memcmp
后有了改进,那么一定要继续。但我不会将其作为常规技术使用ique用于编写比较运算符,即使您的类满足要求。=
更好,因为memcmp
比较纯内存数据(比较
bool operator==(const vector &lhs, const vector &rhs)
{ return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y); }
#include <iostream>
#include <iomanip>
struct A { int * p; };
bool operator== (A const &a, A const &b) { return *(a.p) == *(b.p); }
struct B { A m; };
bool operator== (B const &a, B const &b) { return a.m == b.m; }
int main()
{
int a(1), b(1);
B x, y;
x.m.p = &a;
y.m.p = &b;
std::cout << std::boolalpha;
std::cout << (memcmp(&x, &y, sizeof(B)) == 0) << "\n";
std::cout << (x == y) << "\n";
return 0;
}
false
true
template< class Derived >
struct Relops_from_compare
{
friend
auto operator!=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) != 0; }
friend
auto operator<( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) < 0; }
friend
auto operator<=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) <= 0; }
friend
auto operator==( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) == 0; }
friend
auto operator>=( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) >= 0; }
friend
auto operator>( const Derived& a, const Derived& b )
-> bool
{ return compare( a, b ) > 0; }
};
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
// This implementation assumes no overflow occurs.
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
if( const auto r = a.x - b.x ) { return r; }
if( const auto r = a.y - b.y ) { return r; }
return a.z - b.z;
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
// This implementation requires that there is no padding.
// Also, it doesn't deal with negative numbers for < or >.
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
static_assert( sizeof( Vector ) == 3*sizeof( x ), "!" );
return memcmp( &a, &b, sizeof( Vector ) );
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
struct Vector
: Relops_from_compare< Vector >
{
int x, y, z;
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
if( a.x < b.x ) { return -1; }
if( a.x > b.x ) { return +1; }
if( a.y < b.y ) { return -1; }
if( a.y > b.y ) { return +1; }
if( a.z < b.z ) { return -1; }
if( a.z > b.z ) { return +1; }
return 0;
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
struct Vector
{
int x, y, z;
friend
auto operator<( const Vector& a, const Vector& b )
-> bool
{
using std::tie;
return tie( a.x, a.y, a.z ) < tie( b.x, b.y, b.z );
}
friend
auto operator==( const Vector& a, const Vector& b )
-> bool
{
using std::tie;
return tie( a.x, a.y, a.z ) == tie( b.x, b.y, b.z );
}
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
return (a < b? -1 : a == b? 0 : +1);
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};
struct Vector
{
int x, y, z;
friend
auto operator<( const Vector& a, const Vector& b )
-> bool
{
return (
a.x < b.x ||
a.x == b.x && (
a.y < b.y ||
a.y == b.y && (
a.z < b.z
)
)
);
}
friend
auto operator==( const Vector& a, const Vector& b )
-> bool
{
return
a.x == b.x &&
a.y == b.y &&
a.z == b.z;
}
friend
auto compare( const Vector& a, const Vector& b )
-> int
{
return (a < b? -1 : a == b? 0 : +1);
}
Vector( const int _x, const int _y, const int _z )
: x( _x ), y( _y ), z( _z )
{}
};