将std::字符串数据的深层副本存储到std::vector中
Storing deep copies of std::string data into std::vector
我一定快疯了,但我正在遵循将std::string转换为const char*或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()] = ' '; // 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))
。什么是变通方法?
这个例子说"不要忘记在使用字符串后释放它"。在将地址插入向量后,您立即对内存进行delete
操作。当您稍后尝试访问相同的地址时,这会导致代码非常混乱。
在不讨论您的方法作为一个整体的优点(以及您为什么要做您正在做的事情)的情况下,问题的即时解决方案是只有在使用完向量中的地址后才调用delete
。
请注意,您需要在向量上循环,并在向量中的每个地址上调用delete
。
我决定让一个智能指针来处理我的内存。
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()] = ' '; // don't forget the terminating 0
args.push_back(std::unique_ptr<char[]>(writable));
您遇到valgrind读取问题,因为在"cout<<args[i]<"\n";"行读取"writible"之前已删除。
您应该在引用后将其删除。
相关文章:
- std::原子加载和存储都需要吗
- 如何从存储在std::映射中的std::集中删除元素
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 在std::vector上存储带有模板的类实例
- 在 std::无符号字符的向量处存储 int 的十六进制表示形式
- 将无符号字符的向量存储在数组中会给我 std::bad_alloc
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- 如何访问存储在 std::variant 中的类的方法
- std::vector move 而不是交换到空 vector 并释放存储
- 将可变参数模板类存储到 std::vector 中
- 在 std::vector<无符号字符中存储任意数据的方法>
- 是否可以将具有不同签名的 lambda 存储在 std::vector 中并在函数中执行它们(使用各自的参数)?
- "p"数组如何使用 std::normal_distribution 存储以下代码中的值C++?
- "std::string"是否将其字符作为签名字符在内部存储?
- std::set 是否将对象连续存储在内存中?
- 将数据从 std::Vector 存储到 Eigen::Vector 时出错
- C++:将 std::set_union() 输出存储在 std::multiset 中
- 使用 std::list 存储顶点并使用 SFML 绘制它们
- 从其存储的回调中删除 std::函数是否安全
- 使用 std::map 存储在 std::any 中,然后通过 std::any_cast 访问