C++ 自定义 std::map<>导致内存冲突的键类

C++ Custom std::map<> key class causing memory violation

本文关键字:冲突 内存 自定义 map lt C++ gt std      更新时间:2023-10-16

我第一次写了一个类,它应该是可用的std::map<>的键类型。我已经重载了复制构造函数、赋值和operator <,就像其他关于SO的问题中建议的那样。但由于某种原因,当我试图使用operator []插入时,它崩溃了。该类用于保存二进制数据的缓冲区,其长度由成员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;
   }
};

这门课有什么问题吗?我可以使用std::string<unsigned char>使用二进制数据作为密钥吗?

问题是您没有在复制构造函数或赋值操作符中设置m_nLen成员。因此,每当您使用具有未初始化或错误的m_nLen值的对象时,事情可能会出错,导致可能的崩溃(通常,未定义行为)。

在实现用户定义的复制构造函数和赋值操作符时,应该努力确保最后输出的是所讨论对象的实际副本(引用计数对象是一种特殊情况,但它仍然意味着正在进行复制)。否则,产生不完整或错误对象副本的程序非常脆弱,并且是调试的可怕负担。

请看Paul McKenzie的答案,看看它崩溃的原因。

这门课有什么问题吗?

是的,你的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;
}