C++ 自定义 std::map<> 键 class 导致内存冲突
C++ Custom std::map<> key class causing memory violation
我第一次写了一个 class,它应该可以用作 std::map<>
的键类型。我已经按照其他问题中的建议重载了复制构造函数、赋值和 operator <
。但是由于某种原因,当我尝试使用 operator []
插入时它崩溃了。 class 用于保存二进制数据缓冲区,其长度由成员 m_nLen
.
指示
这是代码:
class SomeKeyClass
{
public:
unsigned char m_buffer[ SOME_LENGTH_CONSTANT ];
size_t m_nLen;
public:
inline SomeKeyClass( const unsigned char * data, size_t nLen )
{
m_nLen = min( SOME_LENGTH_CONSTANT, nLen );
memcpy( m_buffer, data, m_nLen );
}
inline SomeKeyClass( const SomeKeyClass& oKey )
{
*this = oKey;
}
inline bool operator < ( const SomeKeyClass& oKey ) const
{
return memcmp( m_buffer, oKey.m_buffer, min( m_nLen, oKey.m_nLen ) ) < 0;
}
inline SomeKeyClass & operator = ( const SomeKeyClass& oKey )
{
memcpy( m_buffer, oKey.m_buffer, oKey.m_nLen );
return *this;
}
};
这个class有什么问题吗?我可以使用 std::string<unsigned char>
代替二进制数据作为键吗?
问题是您没有在复制构造函数或赋值运算符中设置 m_nLen
成员。因此,每当您使用具有未初始化或错误 m_nLen
值的对象时,事情都可能出错导致可能的崩溃(通常,未定义的行为)。
在实现用户定义的复制构造函数和赋值运算符时,您应该努力确保最后出现的是所讨论对象的实际副本(引用计数对象是一种特殊情况,但它仍然暗示正在复制)。否则,生成不完整或错误的对象副本的程序将非常脆弱,并且会成为调试的沉重负担。
有关崩溃原因,请参阅 Paul McKenzie 的回答。
Is there anything wrong with this class ?
是的,你的 operator<
坏了。
考虑一下你有一个键 "abc" 和另一个键 "abcd" 的情况,你的小于运算符会说它们是等价的,因为你只测试前 3 个字符。
当 memcmp
表示它们相等时,正确的实现需要比较长度,因为 memcmp
调用不一定比较完整的字符串:
bool operator<(const SomeKeyClass& oKey) const
{
const std::size_t len = std::min(m_nLen, oKey.m_nLen);
if (len > 0)
{
const int cmp = memcmp(m_buffer, oKey.m_buffer, len);
if (cmp != 0)
return cmp < 0;
}
return m_nLen < oKey.m_nLen;
}
我第一次写了一个 class,它应该可以用作 std::map<>
的键类型。我已经按照其他问题中的建议重载了复制构造函数、赋值和 operator <
。但是由于某种原因,当我尝试使用 operator []
插入时它崩溃了。 class 用于保存二进制数据缓冲区,其长度由成员 m_nLen
.
这是代码:
class SomeKeyClass
{
public:
unsigned char m_buffer[ SOME_LENGTH_CONSTANT ];
size_t m_nLen;
public:
inline SomeKeyClass( const unsigned char * data, size_t nLen )
{
m_nLen = min( SOME_LENGTH_CONSTANT, nLen );
memcpy( m_buffer, data, m_nLen );
}
inline SomeKeyClass( const SomeKeyClass& oKey )
{
*this = oKey;
}
inline bool operator < ( const SomeKeyClass& oKey ) const
{
return memcmp( m_buffer, oKey.m_buffer, min( m_nLen, oKey.m_nLen ) ) < 0;
}
inline SomeKeyClass & operator = ( const SomeKeyClass& oKey )
{
memcpy( m_buffer, oKey.m_buffer, oKey.m_nLen );
return *this;
}
};
这个class有什么问题吗?我可以使用 std::string<unsigned char>
代替二进制数据作为键吗?
问题是您没有在复制构造函数或赋值运算符中设置 m_nLen
成员。因此,每当您使用具有未初始化或错误 m_nLen
值的对象时,事情都可能出错导致可能的崩溃(通常,未定义的行为)。
在实现用户定义的复制构造函数和赋值运算符时,您应该努力确保最后出现的是所讨论对象的实际副本(引用计数对象是一种特殊情况,但它仍然暗示正在复制)。否则,生成不完整或错误的对象副本的程序将非常脆弱,并且会成为调试的沉重负担。
有关崩溃原因,请参阅 Paul McKenzie 的回答。
Is there anything wrong with this class ?
是的,你的 operator<
坏了。
考虑一下你有一个键 "abc" 和另一个键 "abcd" 的情况,你的小于运算符会说它们是等价的,因为你只测试前 3 个字符。
当 memcmp
表示它们相等时,正确的实现需要比较长度,因为 memcmp
调用不一定比较完整的字符串:
bool operator<(const SomeKeyClass& oKey) const
{
const std::size_t len = std::min(m_nLen, oKey.m_nLen);
if (len > 0)
{
const int cmp = memcmp(m_buffer, oKey.m_buffer, len);
if (cmp != 0)
return cmp < 0;
}
return m_nLen < oKey.m_nLen;
}