使用memcpy重构字符串流的使用

Refactoring use of stringstreams with memcpy

本文关键字:字符串 memcpy 重构 使用      更新时间:2023-10-16

我得到了这个代码:

  class Record
    {
   private:
      unsigned short size_of_buffer;
      char* buffer;
   public:
      bool was_marked_as_deleted();
    };  

bool Record::was_marked_as_deleted(){
        if (buffer == NULL)
            return false;
        stringstream stream;
        stream.write(buffer,size_of_buffer);
        stream.seekg(0,stream.beg);
        unsigned short size_of_first_field = 0;
        stream.read( (char*)(&size_of_first_field) , sizeof(size_of_first_field) );
        if (size_of_first_field > 1)
            return false;
        char first_field = 1;
        stream.read( (char*)(&first_field) , sizeof(first_field) );
        if ( first_field != MARK_DELETED )
            return false;
        return true; 
    }

上述功能为

  • 非常低效,因为stream.write(buffer,size_of_buffer);线路
  • 无法读取

所以我想用memcpy而不是stringstreams重构它。这就是我想到的:

bool Record::was_marked_as_deleted(){
    if(buffer==NULL)
        return false;
    unsigned short size_of_first_field= 0;
    memcpy(&size_of_first_field,buffer,sizeof(size_of_first_field));
    if (size_of_first_field > 1)
        return false;
    char first_field = 1;
    //This line produces valgrind error
    //EDIT: fixed it with the following IF statement
    if (size_of_buffer > sizeof(size_of_first_field))
         memcpy(&first_field,buffer+sizeof(size_of_first_field),sizeof(first_field));
    if (first_field != MARK_DELETED )
        return false;
    return true;
}

现在,问题是我的程序运行得很好,但当我用valgrind运行它时,我得到的是:

==17340== Invalid read of size 1
==17340==    at 0x8059452: Record::was_marked_as_deleted() (Record.cpp:161)
==17340==  Address 0x5af2832 is 0 bytes after a block of size 2 alloc'd

为什么会这样?为什么我的程序在valgrind下失败,而在正常执行时却没有?

std::stringstreammemcpy对于这种类型的操作都是低效的。只需像这样直接访问缓冲区…

bool Record::was_marked_as_deleted()
{
    if (buffer == NULL || size_of_buffer < 3)
        return false;
    unsigned short size_of_first_field
        = reinterpret_cast<unsigned short*>(buffer)[0];
    if (size_of_first_field > 1)
        return false;
    if (buffer[3] != MARK_DELETED)
        return false;
    return true;
}

或者使用数据结构。。。

bool Record::was_marked_as_deleted()
{
    if (buffer == NULL || size_of_buffer < 3)
        return false;
    // Add packing directives if necessary. i.e. #pragma pack
    struct Data { unsigned short size; char flag; };
    Data *field = reinterpret_cast<Data*>(buffer);
    if (field->size > 1)
        return false;
    if (field->flag != MARK_DELETED)
        return false;
    return true;
}