【问题标题】:C++ Custom std::map<> key class causing memory violationC++ 自定义 std::map<> 键类导致内存冲突
【发布时间】:2015-06-09 16:01:52
【问题描述】:

我第一次编写了一个可以用作std::map&lt;&gt; 的键类型的类。我已经重载了复制构造函数、赋值和operator &lt;,正如其他关于 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&lt;unsigned char&gt; 来代替使用二进制数据作为键吗?

【问题讨论】:

  • 您没有在复制构造函数和赋值运算符中设置m_nLen 成员。是的,std::string 可用于二进制数据。但是您不需要覆盖复制构造函数或赋值运算符——结构或类中的数组将正确复制。
  • 是的,现在可以了,谢谢。
  • 为了使其防弹,您应该在 memcpy 等之前检查零长度。您可能认为 0 等于无操作,但我曾看到意外通过 0 时发生崩溃。
  • 我建议使用std::vector&lt;unsigned char&gt; 来处理简单的二进制缓冲区。比std::string 更好,比原始指针更简单、更安全。
  • @donjuedo memcmp(p1, p2, 0) 如果p1p2 为空,则为未定义行为

标签: c++ templates dictionary stl key


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    查看 Paul McKenzie 的回答,了解它崩溃的原因。

    这个类有什么问题吗?

    是的,你的operator&lt; 坏了。

    假设您有一个键“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;
    }
    

    【讨论】:

    • 谢谢,这可以解释我遇到的一些问题。如果它们的长度相等,那么最短的也是最小的吧?
    • 是的,没错,我已经用正确的实现更新了答案。
    猜你喜欢
    • 2012-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 2023-03-08
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多