1

I use unique_ptr. For creating this poiters, I use this code snippet:

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); //line 44
}

I test my project for memory leaks with help built-in memory leak checker.

I get the following result:

Detected memory leaks!
Dumping objects ->
my_header.h(44) : {228} normal block at 0x008AD568, 8 bytes long.
 Data: <        > A0 CB 8A 00 01 00 00 00 
my_header.h(44) : {226} normal block at 0x008AD5B8, 8 bytes long.
 Data: <        > 00 D6 8A 00 00 00 00 00 
/////////////////this error repeats many times

Also, I use deleaker. This tool says, that there is no memory leaks.

Denis
  • 3,595
  • 12
  • 52
  • 86
  • Don't use this for array types? – Kerrek SB May 31 '15 at 00:58
  • @KerrekSB, I use make_unique 3 times in my project. make_unique always create raw pointer. I see this code - http://stackoverflow.com/a/13512344/1756750 My error is reproduced with this code too. – Denis May 31 '15 at 01:03
  • Using `return` with a `unique_ptr` automatically calls [move](http://en.cppreference.com/w/cpp/utility/move) -- I take it this is what you want? – erip May 31 '15 at 01:08
  • @erip, unfortunately, I don't use `return` with a `unique_ptr`. I just create unique_ptr and call `release()`. – Denis May 31 '15 at 01:13
  • @Denis, in your code `make_unique` does indeed `return` a `unique_ptr`. Perhaps the memory-leak checker thinks that this reference within `make_unique` is a leak, when it actually isn't because ownership is moving to the assignee when called. – erip May 31 '15 at 01:15
  • @erip, Right. Initially, I misunderstood you, sorry. – Denis May 31 '15 at 01:17
  • Wait, why are you calling `release()`? – T.C. May 31 '15 at 01:28
  • 2
    @erip Technically, it doesn't call `std::move`. – T.C. May 31 '15 at 01:32
  • @T.C. would this be a case of RVO and that's why `std::move` isn't called? – Alejandro May 31 '15 at 03:28

1 Answers1

1

You shouldn't be using release() unless you're handing off the pointer-raw to someone else (hopefully another std::unique_ptr or a std::shared_ptr, etc). Instead you should be using reset(), or just letting scope-exit destroy the managed object for you.

The simplest example using your code that demonstrates bad and good:

Bad : Using release()

#include <memory>

namespace
{
    template<typename T, typename ...Args>
    std::unique_ptr<T> make_unique(Args&& ...args)
    {
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}

int main()
{
    std::unique_ptr<int> ptr = make_unique<int>(5);
    ptr.release();
}

Valgrind Output

==29012== 4 bytes in 1 blocks are definitely lost in loss record 1 of 87
==29012==    at 0x10003B51B: malloc (vg_replace_malloc.c:303)
==29012==    by 0x1001CD43D: operator new(unsigned long) (in /usr/lib/libc++.1.dylib)
==29012==    by 0x10000147B: std::__1::unique_ptr<int, std::__1::default_delete<int> > (anonymous namespace)::make_unique<int, int>(int&&) (in ./Sample C++)
==29012==    by 0x100001337: main (in ./Sample C++)
==29012== 
==29012== LEAK SUMMARY:
==29012==    definitely lost: 4 bytes in 1 blocks
==29012==    indirectly lost: 0 bytes in 0 blocks
==29012==      possibly lost: 0 bytes in 0 blocks
==29012==    still reachable: 192 bytes in 6 blocks
==29012==         suppressed: 35,164 bytes in 435 blocks
==29012== Reachable blocks (those to which a pointer was found) are not shown.
==29012== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==29012== 
==29012== For counts of detected and suppressed errors, rerun with: -v
==29012== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 17 from 17)

Good: Using reset()

#include <memory>

namespace
{
    template<typename T, typename ...Args>
    std::unique_ptr<T> make_unique(Args&& ...args)
    {
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}

int main()
{
    std::unique_ptr<int> ptr = make_unique<int>(5);
    ptr.reset(); // HERE
}

Valgrind Output

==29045== HEAP SUMMARY:
==29045==     in use at exit: 35,356 bytes in 441 blocks
==29045==   total heap usage: 508 allocs, 67 frees, 41,216 bytes allocated
==29045== 
==29045== LEAK SUMMARY:
==29045==    definitely lost: 0 bytes in 0 blocks
==29045==    indirectly lost: 0 bytes in 0 blocks
==29045==      possibly lost: 0 bytes in 0 blocks
==29045==    still reachable: 192 bytes in 6 blocks
==29045==         suppressed: 35,164 bytes in 435 blocks
==29045== Reachable blocks (those to which a pointer was found) are not shown.
==29045== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==29045== 
==29045== For counts of detected and suppressed errors, rerun with: -v
==29045== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 17 from 17)

The same output as above (the Good) is received by simply removing the second line in main() entirely.

int main()
{
    std::unique_ptr<int> ptr = make_unique<int>(5);
}

And likewise with this:

int main()
{
    std::unique_ptr<int> ptr = make_unique<int>(5);
    std::unique_ptr<int> other(ptr.release());
}

Best of luck.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141