8
\$\begingroup\$

I carefully used smart pointer to avoid memory leaks and dangling pointers, but someone says my code has memory leaks. Is it true? If so, how can I fix it?

#include <iostream>
#include <initializer_list>
#include <memory>

using namespace std;
using Ptr2D = unique_ptr<unique_ptr<int[]>[]>;
using IniList = initializer_list<int>;

void printImage(const Ptr2D& image, const IniList& il)
{
    for (auto& i : il)
    {
        for (auto& j : il)
        {
            cout << image[i][j] << ',';
        }

        cout << '\n';
    }
}

template<size_t SIZE>
void rotateImage(Ptr2D& image, const IniList& il)
{
    Ptr2D temp(new unique_ptr<int[]>[SIZE]);

    for (auto& i : il)
    {
        unique_ptr<int[]> subTemp(new int[SIZE]);

        for (auto& j : il)
        {
            subTemp[j] = 0;
        }

        temp[i] = move(subTemp);
    }

    for (auto& i : il)
    {
        for (auto& j : il)
        {
            temp[i][j] = image[SIZE - j - 1][i];
        }
    }

    for (auto& i : il)
    {
        for (auto& j : il)
        {
            image[i][j] = move(temp[i][j]);
        }
    }
}

int main()
{
    const size_t SIZE = 5;

    Ptr2D image(new unique_ptr<int[]>[SIZE]);

    IniList il = { 0, 1, 2, 3, 4 };

    for (auto& i : il)
    {
        unique_ptr<int[]> temp(new int[SIZE]);

        for (auto& j : il)
        {
            temp[j] = j + il.size() * i;
        }

        image[i] = move(temp);
    }

    cout << "******* original image ******\n";

    printImage(image, il);

    rotateImage<SIZE>(image, il);

    cout << "******* rotated image ******\n";

    printImage(image, il);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Seems like it would be easier to do std::vector<std::vector<int>> or just std::vector<int> \$\endgroup\$ – Martin York Dec 16 '14 at 19:06
5
\$\begingroup\$

At a quick glance there doesn't appear to be any memory leaks:

valgrind ./mem_leak_test
==3914== Memcheck, a memory error detector
==3914== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==3914== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==3914== Command: ./mem_leak
==3914== 
******* original image ******
0,1,2,3,4,
5,6,7,8,9,
10,11,12,13,14,
15,16,17,18,19,
20,21,22,23,24,
******* rotated image ******
20,15,10,5,0,
21,16,11,6,1,
22,17,12,7,2,
23,18,13,8,3,
24,19,14,9,4,
==3914== 
==3914== HEAP SUMMARY:
==3914==     in use at exit: 0 bytes in 0 blocks
==3914==   total heap usage: 12 allocs, 12 frees, 296 bytes allocated
==3914== 
==3914== All heap blocks were freed -- no leaks are possible
==3914== 
==3914== For counts of detected and suppressed errors, rerun with: -v
==3914== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

Valgrind appears to agree about the lack of memory leaks.

I would just use std::array instead of code such as unique_ptr<int[]> temp(new int[SIZE]);. You get the benefits of automatic memory cleanup at the end of the variables scope from std::array without as much complexity. The main reason I would go for std::array is because you appear to be mostly concerned with memory management and not ownership. However if your intent here is to clearly have single ownership then unique_ptr is a good choice.

std::array will reduce complexity because it contains information about its dimensions. This would completely remove the need for the initializer list for initializing the array. Unless you are going to do something more fancy with it, the initializer list is an overly complex way to iterate over all the indexes of an array.

Assuming we changed this to use std::array the other thing I would do differently is to return the rotated image from rotateImage as opposed to modifying a reference parameter. Fewer side effects tends to keep your code more conceptually simple.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.