2013-07-02 56 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; 
}