0

I wrote a small piece of code like this:

template <class T>
void
test()
{
    T* ptr = nullptr;

    ptr = (T*)malloc(1 * sizeof(T));

    new ((void*)ptr) T(T());

    ptr = (T*)realloc(ptr, 2 * sizeof(T));

    new ((void*)(ptr + 1)) T(T());

    (ptr)->~T();
    (ptr + 1)->~T();

    free(ptr);
}

struct foo
{
    foo() : ptr(malloc(10)) {}
    ~foo() { free(ptr); } 
    void* ptr;
};

int
main()
{ 
    test<int>(); // this is ok
    test<foo>(); // this is ok
    test<std::string>(); // memory error :(

    return 0;
}; 

When T is [int] or [foo], everything works fine. But using [std::string] as T causes valgrind to report memory errors like this:

==18184== Memcheck, a memory error detector
==18184== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18184== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18184== Command: ./a.out
==18184== 
==18184== Invalid free() / delete / delete[] / realloc()
==18184==    at 0x4C2C20A: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x401074: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:26)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184==  Address 0x5a89e70 is 16 bytes inside a block of size 32 free'd
==18184==    at 0x4C2CC37: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x401042: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:22)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184==  Block was alloc'd at
==18184==    at 0x4C2AB8D: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184==    by 0x40100F: void test<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >() (tmp.cpp:18)
==18184==    by 0x400CFC: main (tmp.cpp:44)
==18184== 
==18184== 
==18184== HEAP SUMMARY:
==18184==     in use at exit: 0 bytes in 0 blocks
==18184==   total heap usage: 9 allocs, 10 frees, 72,856 bytes allocated
==18184== 
==18184== All heap blocks were freed -- no leaks are possible
==18184== 
==18184== For counts of detected and suppressed errors, rerun with: -v
==18184== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

why only [std::string] leads to memory problem while [foo] also has malloc/free in both ctor & dtor ?

I'm using g++ 6.2.1 and valgrind 3.12.0

0

2 Answers 2

3

malloc(), free(), and realloc() are C library functions, that know absolutely nothing about C++ classes, their constructors, and destructors.

You are using malloc() with placement new to construct a std::string using malloc-ed memory. This is fine.

But then, you're using realloc() to reallocate the allocated memory.

Copying/moving C++ objects in memory must be done using the respective objects' copy/move constructors. Copying/moving C++ objects in memory cannot be done with realloc().

The only way to do this is to malloc() a new memory block, use placement new to invoke the objects' copy/move constructors in order to copy/move them into the new memory block, and finally invoke the destructor of the objects in the old memory block, after which it can be free()-ed.

Sign up to request clarification or add additional context in comments.

Comments

2

realloc is not compatible with non-POD types.

Because it can move things in memory without the moved objects being aware of it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.