2014-09-26 63 views
0

我一定要瘋了,但我在Convert std::string to const char* or char*的例子之後,我在valgrind中得到了很多Invalid read of size 1。我基本上試圖分割空白分隔的字符串,並將它們存儲到std::vector<const char*>。我知道,因爲從c_str()返回的指針可能隨時失效,您必須執行一個副本才能安全地使用數據。但是,自從valgrind抱怨之後,我似乎一定會失去一些東西。在絕對最低,我複製了頂部的答案,這樣做:將std :: string數據的深拷貝存儲到std :: vector中

#include <iostream> 
#include <sstream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    std::vector<const char*> args; 

    std::string str = "hey"; 

    char * writable = new char[str.size() + 1]; 
    std::copy(str.begin(), str.end(), writable); 
    writable[str.size()] = '\0'; // don't forget the terminating 0 
    args.push_back(writable); 
    delete[] writable; 

    for (size_t i = 0; i < args.size(); ++i) 
     cout << args[i] << "\n"; 

    return 0; 
} 

下面的輸出,這導致從Valgrind的:

==5297== Invalid read of size 1 
==5297== at 0x4C2BFC2: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CFF: main (in /tmp/1411705143.17426/a.out) 
==5297== Address 0x5c2a0a0 is 0 bytes inside a block of size 4 free'd 
==5297== at 0x4C2A09C: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CD9: main (in /tmp/1411705143.17426/a.out) 
==5297== 
==5297== Invalid read of size 1 
==5297== at 0x4C2BFD4: __GI_strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CFF: main (in /tmp/1411705143.17426/a.out) 
==5297== Address 0x5c2a0a1 is 1 bytes inside a block of size 4 free'd 
==5297== at 0x4C2A09C: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CD9: main (in /tmp/1411705143.17426/a.out) 
==5297== 
==5297== Invalid read of size 1 
==5297== at 0x58E6DB8: _IO_default_xsputn (genops.c:480) 
==5297== by 0x58E4D19: [email protected]@GLIBC_2.2.5 (fileops.c:1393) 
==5297== by 0x58DA98C: fwrite (iofwrite.c:45) 
==5297== by 0x4EC8A35: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (streambuf:451) 
==5297== by 0x400D0F: main (in /tmp/1411705143.17426/a.out) 
==5297== Address 0x5c2a0a0 is 0 bytes inside a block of size 4 free'd 
==5297== at 0x4C2A09C: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CD9: main (in /tmp/1411705143.17426/a.out) 
==5297== 
==5297== Invalid read of size 1 
==5297== at 0x58E6DC7: _IO_default_xsputn (genops.c:479) 
==5297== by 0x58E4D19: [email protected]@GLIBC_2.2.5 (fileops.c:1393) 
==5297== by 0x58DA98C: fwrite (iofwrite.c:45) 
==5297== by 0x4EC8A35: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (streambuf:451) 
==5297== by 0x400D0F: main (in /tmp/1411705143.17426/a.out) 
==5297== Address 0x5c2a0a2 is 2 bytes inside a block of size 4 free'd 
==5297== at 0x4C2A09C: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==5297== by 0x400CD9: main (in /tmp/1411705143.17426/a.out) 
==5297== 

我懷疑,這種解決方案並不因爲工作刪除後,矢量內的數據指向垃圾。我也試過args.push_back(std::move(writable))。什麼是解決方法?

+2

爲什麼不直接存儲'std :: string'?爲什麼要讓自己頭疼存儲'char'數組副本? – Brandon 2014-09-26 04:36:58

回答

2

這個例子說「使用它之後不要忘記釋放字符串「。你是delete - 將地址插入向量後立即進入內存。當您嘗試稍後訪問相同的地址時,這會導致代碼非常糟糕。

沒有深入研究整個方法的優點(以及爲什麼要做自己正在做的事情),解決問題的直接方法是隻有在完成地址的使用後才調用delete在向量中。

請注意,您需要遍歷向量並在矢量中的每個地址上調用delete

0

我決定讓一個智能指針處理我的記憶。

std::vector<std::unique_ptr<char[]>> args; 

std::string str = "hey"; 

char * writable = new char[str.size() + 1]; 
std::copy(str.begin(), str.end(), writable); 
writable[str.size()] = '\0'; // don't forget the terminating 0 
args.push_back(std::unique_ptr<char[]>(writable)); 
+0

哦,親愛的。使用'std :: vector args;'後面跟着'args.emplace_back(str);'或'args.emplace_back(pointer_to_first_character,num_characters);' - 使用'args.push_back(std :: string( pointer_to_first_character,num_characters));'如果仍然在C++ 03上。如果原始字符串/緩衝區處於懸停狀態,則可以編寫一個'類Const_Text_By_Pointer {const char * p_; size_t n_; ...};'只要原始文件可以使用它,就可以根據需要補償缺少終止NUL的類 - 這會更快並且使用更少的內存。 – 2014-09-26 05:48:02

0

你得到的valgrind讀的問題,因爲 '寫' 在線上讀 「COUT < < ARGS [I] < < 」之前\ n刪除「;」。

您應該在引用它之後刪除它。

相關問題