내 프로젝트에 주로 std::vector
요소를 저장하는 클래스가 있고이 클래스의 이진 표현을 저장하고로드 할 수 있어야합니다. 디스크에서 /로 객체. 객체가 파일을로드하면 변수의 요소 수를 읽은 다음 저장된 요소를 배열로 읽습니다. 이 배열에서 요소를 벡터 멤버에 푸시합니다. 내가 명시 적으로 calloc
또는 new
을 호출하지 않은 것처럼 C++에서 메모리를 처리하도록했습니다. 잘 작동하지만 Valgrind는 잘못된 읽기 및 쓰기에 대한 일부 오류 메시지를 제공하므로 이해가되지 않습니다. 그것들은 클래스 소멸자에서 비롯된 것 같지만 클래스에는 "동적 인"요소 인 std::vector
요소 만 있으므로 거기에서 아무 것도 할 필요가 없습니까?Valgrind는 잘못된 읽기/쓰기 오류를 표시하지만 new 또는 calloc은 벡터 및 고정 배열 만 사용하지 않습니다.
이 작동 최소한의 예입니다 : 내가 컴파일하고 Valgrind의에서 이것을 실행하면,
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
class Test {
public:
Test() {}
~Test() {}
void add(std::string s) { v.push_back(s); }
std::vector<std::string>& get() { return v; }
void store(char const* path) {
std::ofstream file(path, std::ios_base::out | std::ios_base::binary);
unsigned int n = v.size();
file.write((char*) &n, sizeof(unsigned int));
file.write((char*) v.data(), n*sizeof(std::string));
file.close();
}
void read(char const* path) {
std::ifstream file(path, std::ios_base::in | std::ios_base::binary);
unsigned int n;
file.read((char*) &n, sizeof(unsigned int));
std::string in_v[n];
file.read((char*) in_v, n*sizeof(std::string));
v.clear();
for (unsigned int i = 0; i < n; i++) {
v.push_back(in_v[i]);
}
if (!file) { throw std::runtime_error("reading failed"); }
}
private:
std::vector<std::string> v;
};
std::ostream& operator<<(std::ostream& os, Test& t) {
for (unsigned int i = 0; i < t.get().size(); i++) {
os << t.get()[i] << std::endl;
}
return os;
}
int main(int argc, char *argv[]) {
Test a;
a.add("foo");
a.add("bar");
std::cout << a << std::endl;
a.store("file");
//Test b;
//b.read("file");
//std::cout << "restored:" << std::endl << b << std::endl;
return 0;
}
모든 예상 누출이 감지되지로 작동합니다
==24891== Memcheck, a memory error detector
==24891== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==24891== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==24891== Command: ./dummy
==24891==
foo
bar
==24891==
==24891== HEAP SUMMARY:
==24891== in use at exit: 72,704 bytes in 1 blocks
==24891== total heap usage: 7 allocs, 6 frees, 81,528 bytes allocated
==24891==
==24891== LEAK SUMMARY:
==24891== definitely lost: 0 bytes in 0 blocks
==24891== indirectly lost: 0 bytes in 0 blocks
==24891== possibly lost: 0 bytes in 0 blocks
==24891== still reachable: 72,704 bytes in 1 blocks
==24891== suppressed: 0 bytes in 0 blocks
==24891== Rerun with --leak-check=full to see details of leaked memory
==24891==
==24891== For counts of detected and suppressed errors, rerun with: -v
==24891== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
을하지만 최대한 빨리의 주석으로 main()
함수의 마지막 줄은 여전히 모두 이며,이 작동하지만 valgrind는 몇 가지 메시지를 인쇄하고 그 이유를 알지 못합니다.
foo
bar
restored:
foo
bar
==4004== Invalid read of size 4
==4004== at 0x4F04610: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015B0: main (dummy.cpp:48)
==4004== Address 0x5aa8c90 is 16 bytes inside a block of size 28 free'd
==4004== at 0x4C2A184: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004== by 0x4F04603: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015A4: main (dummy.cpp:56)
==4004==
==4004== Invalid write of size 4
==4004== at 0x4F04616: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015B0: main (dummy.cpp:48)
==4004== Address 0x5aa8c90 is 16 bytes inside a block of size 28 free'd
==4004== at 0x4C2A184: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004== by 0x4F04603: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015A4: main (dummy.cpp:56)
==4004==
==4004== Invalid free()/delete/delete[]/realloc()
==4004== at 0x4C2A184: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004== by 0x4F04603: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015B0: main (dummy.cpp:48)
==4004== Address 0x5aa8c80 is 0 bytes inside a block of size 28 free'd
==4004== at 0x4C2A184: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004== by 0x4F04603: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib64/libstdc++.so.6.0.21)
==4004== by 0x4026CE: void std::_Destroy<std::string>(std::string*) (stl_construct.h:93)
==4004== by 0x402534: void std::_Destroy_aux<false>::__destroy<std::string*>(std::string*, std::string*) (stl_construct.h:103)
==4004== by 0x4021FD: void std::_Destroy<std::string*>(std::string*, std::string*) (stl_construct.h:126)
==4004== by 0x401D76: void std::_Destroy<std::string*, std::string>(std::string*, std::string*, std::allocator<std::string>&) (stl_construct.h:151)
==4004== by 0x401B5B: std::vector<std::string, std::allocator<std::string> >::~vector() (stl_vector.h:424)
==4004== by 0x4016E5: Test::~Test() (dummy.cpp:9)
==4004== by 0x4015A4: main (dummy.cpp:56)
==4004==
==4004==
==4004== HEAP SUMMARY:
==4004== in use at exit: 72,704 bytes in 1 blocks
==4004== total heap usage: 11 allocs, 12 frees, 90,296 bytes allocated
==4004==
==4004== LEAK SUMMARY:
==4004== definitely lost: 0 bytes in 0 blocks
==4004== indirectly lost: 0 bytes in 0 blocks
==4004== possibly lost: 0 bytes in 0 blocks
==4004== still reachable: 72,704 bytes in 1 blocks
==4004== suppressed: 0 bytes in 0 blocks
==4004== Rerun with --leak-check=full to see details of leaked memory
==4004==
==4004== For counts of detected and suppressed errors, rerun with: -v
==4004== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 0 from 0)
이 오류의 원인은 무엇입니까? 나는 read
메쏘드를 가지고 뭔가있을 것이라고 기대하지만, 왜 valgrind는 이전에 아무런 오류가 없었던 a
("dummy.cpp : 48")의 생성에서 오류를 보여줍니까?
'std :: string in_v [n]; '은 VLA이며 트리거 된 것일 수 있습니다. 배열 크기가 알려지지 않은 경우라면'std :: vector'를 사용해야합니다. – NathanOliver
'file.read ((char *) in_v, n * sizeof (std :: string));'look _really_ dodgy –
@NathanOliver 조언을 주셔서 감사합니다, 그냥''v.resize (n);과''file.read (char *) v.data(), n * sizeof (std :: string)); 이것도 잘 작동하지만 valgrind 오류가 발생합니다. 메서드의 끝에 std :: stiring * in_v = new std :: string [n]과 delete []를 명시 적으로 할당하면 동일합니다. – mable