free():删除动态数组时在 tcache 2 中检测到双重释放

free(): double free detected in tcache 2 while deleting dynamic array

我正在尝试读取 .txt 文件并打印行,同时仅使用 c 风格的字符串。

int main(int argc, char * argv[]){
   ...

   size_t size = 2;
   char* line = new char[size];
   char c;
   while (file.get(c)) {
       if(c != '\n'){
          line[size - 2] = c;
          char* temp = new char[size + 1];
          memcpy(temp, line, size * sizeof(char));
          delete[] line;
          line = temp;
          delete[] temp;
          size++;
        } else{
           line[size - 1] = '\n';
           cout << line << endl;
           delete [] line;
           size = 2;
           line = new char[size];
        }
   }
...
}

我收到错误 free(): double free detected in tcache 2。有什么问题,如何解决?

I am getting the error free(): double free detected in tcache 2. What is the problem and how can fix it?

通过理解这段代码的错误:

char* temp = new char[size + 1];
memcpy(temp, line, size * sizeof(char));
delete[] line;
line = temp;
delete[] temp;

要记住的重要一点是 templine 指向字符数组的指针 ;也就是说,它们可以 refer 一个数组,但它们不(通过它们自己)代表数组的 copies。所以:

// sets (line) to a memory address where (size) bytes have been
// made available for you to use.  Let's assume (line) gets set to
// 0x11223344
char* line = new char[size];

[...]

// sets (temp) to the memory address where (size+1) bytes have been
// made available for you to use.  For the sake of the exmaple, 
// let's assume (temp) gets set here to memory-address 0x12345678.
char* temp = new char[size + 1];

// Copies (size) bytes from (line) (aka starting at  memory-address 0x11223344)
// to (temp) (aka starting at memory-address 0x12345678)  
memcpy(temp, line, size * sizeof(char));

// tells the heap that you no longer need the byte-array starting at 0x11223344.
// After this delete[] returns, the heap is allowed to reuse those
// bytes for other (unrelated) things, so you are no longer allowed to 
// read or write that memory region!
delete[] line;

// Sets the value of the (line) pointer to point to 0x12345678 instead.
line = temp;

// tells the heap that you no longer need the bytes starting at 0x12345678.
// After this delete[] returns, the heap is allowed to use those
// bytes for other (unrelated) things, so you are no longer allowed to 
// read or write that memory region!    
delete[] temp;

// Note that at this point, (line) is still pointing to 0x1234568, *but*
// you are no longer allowed to use the memory at that address!
// This is a problem, because on the next iteration of your while-loop,
// you are going to write to either line[size-2] or line[size-1]; either
// either way you are writing to freed memory, which will invoke 
// undefined behavior and cause problems for you.

那么,如何解决这个问题?正如评论中所建议的那样,解决它的最佳方法是完全避免 newdelete[],而是坚持使用 std::string,因为这样可以避免所有常见的悬挂问题指针、释放后使用、未初始化的内存读取、未终止的字符串等

如果您必须使用newdelete[],但是(例如因为这是分配规则),那么您需要跟踪每个堆分配的生命周期;在这种情况下,这意味着意识到当您设置 line = temp; 时,这意味着 line 现在指向 相同的 数组 temp 指向,并且由于您的代码希望在将来使用该数组,因此您不应调用 delete[] temp; 因为它会删除 line 指向的堆分配,并将 line 保留为悬挂指针(即指向您不再被允许使用的内存)。