将std :: string数据的深层副本存储到std :: vector中

时间:2014-09-26 04:30:01

标签: c++ string vector valgrind

我一定是疯了,但是我正在关注Convert std::string to const char* or char*中的例子,我在valgrind中得到了很多Invalid read of size 1。我基本上尝试拆分空白分隔字符串并将它们存储到std::vector<const char*>中。我知道因为c_str()返回的指针随时都可能无效,所以你必须执行一个副本才能安全地使用数据。但是,由于valgrind抱怨,似乎我必须遗漏一些东西。在最低限度,我正在复制最佳答案并执行此操作:

#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: _IO_file_xsputn@@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: _IO_file_xsputn@@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))。什么是变通方法?

3 个答案:

答案 0 :(得分:2)

示例说明&#34;请勿忘记在使用之后释放字符串 &#34;。在将地址插入向量后,您立即重新delete内存。当您稍后尝试访问相同的地址时,这会导致代码损坏。

如果不考虑整个方法的优点(以及为什么你正在做你正在做的事情),问题的直接解决方法是只在你做完之后再调用delete使用向量中的地址完成。

请注意,您需要循环向量并在向量中的每个地址上调用delete

答案 1 :(得分: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));

答案 2 :(得分:0)

你正在获得valgrind阅读问题,因为&#39;可写&#39;在被读取之前被删除&#34; cout&lt;&lt; args [i]&lt;&lt; &#34; \ n&#34 ;;&#34 ;.

引用后应删除它。