使用memcpy重构stringstreams的使用

时间:2013-07-02 18:51:53

标签: c++ valgrind memcpy stringstream

我得到了这段代码:

  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下失败但在正常执行时失败?

1 个答案:

答案 0 :(得分:1)

这种类型的操作对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;
}