2013-07-02 28 views
0

重构使用stringstreams的我被赋予这样的代码:用的memcpy

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下失败,而不是正常执行?

+0

为什么这么说stream.write是非常低效的?它甚至没有对输入进行任何检查。这是否被实时调用?或者是一个非常大的时间?如果不是这样,你可能不会注意到它的差别 – Pedrom

+0

它被称为很多次。函数不会将'buffer'的内容复制到流中? –

+0

就像memcpy一样,你不会看到区别。检查一下Obvlious队长说什么是我准备给你的答案。 – Pedrom

回答

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; 
}