Does using references instead of pointers, resolve

2019-01-20 08:26发布

问题:

Most of memory leaks appear when a pointer of an object returned and programmer forgot to delete it.

for example:

class my_class
{
  ...
};

my_class* func1()
{
  my_class* c = new my_class;
  return c;
}

int main()
{
  my_class* var1 = func1();
  ...
  // Programmer forgot delete the var1: delete var1;
  // -- or --
  // Doesn't know 'delete[] var1;' is correct or 'delete var1;'.
}

Some of memory leaks appear when a pointer to an object created and programmer forgot to delete it.

for example:

class my_class
{
  ...
};

void func2(my_class* p)
{
  ...
}

int main()
{
  my_class* var3 = new my_class;

  func2(var3);

  // Does func2 deletes var3? Programmer doesn't know.
  // -- or --
  // Programmer forgot delete the var3.
}

I use a method to resolve memory leaks but I don't sure about it in complex situations.

My method is: Don't use any pointers (except one place), Just use references instead of pointers.

for example:

class my_class
{
  ...
};

my_class& func1()
{
  my_class* c = new my_class; // except one place.
  return *c;
}

void func2(my_class& p)
{
  ...
}

int main()
{
  my_class& var1 = func1();
  my_class  var2 = func1();

  my_class var3;
  func2(var3);

  // There is nothing to forget.
}

Does using references instead of pointers, resolve memory leaks?

Is it a good method for resolving memory leaks or there are better methods?


Edit:

Some answer of this question don't agree the below code don't have memory leak.

because it is a new question, I ask it seperately.

class my_class
{
  ...
};

my_class& func()
{
  my_class* c = new my_class;
  return *c;
}

int main()
{
  my_class& var1 = func();

  // I think there is no memory leak.
}

I ask it here: Does this code leak memory? (references, new, but no delete)

回答1:

You haven't resolved any memory leaks. If you new, then you must delete. All you did was dereference the pointer, it still needs to be deleted. You can resolve memory leaks by creating local objects and returning by value, or using smart pointers. 99 times out of 100, I prefer the return by value option.

Now, like many beginners, the idea of returning large objects by value probably scares your perf-centric mind. Read this to allay your fears.



回答2:

Your approach does not help at all:

Foo & magic()
{
  return * new Foo();  // dynamically allocated
}

int main()
{
  Foo x = magic();     // copied and lost
  Foo & y = magic();   // reference, still holding on
  delete &y;           // phew, and ewww
}

You are still just allocating the object dynamically and have to take care of it manually! In fact, my first usage makes a copy of the reference and then forgets the reference, creating an instant leak! And even if you did still somehow retain the reference, as in the second example, it becomes entirely unmanageable! (See Soap's comment.)

So please just forget about this entire idea quickly and look at resource managing containers instead!

For example:

#include <memory>

typedef std::shared_ptr<Foo> FooPtr;

FooPtr makeFoo()
{
  // return FooPtr(new Foo);       // Baby's first smart pointer
  return std::make_shared<Foo>();  // Adult approach to shared_ptr
}

int main()
{
  FooPtr pf = makeFoo();

  someFooModifier(*pf);
}


回答3:

Don't return raw pointers from functions; stick them in a smart pointer class such as unique_ptr or shared_ptr. Then you don't have to worry about deleting the allocated object.

Also, in your second example, who is deleting the object allocated by func1()? Just because you return a reference instead of pointer doesn't mean freeing of allocated memory will happen magically.



回答4:

Yes there is a memory leak. The following code is executed with valgrind :

#include <iostream>

class my_class
{
    public :
    my_class(void)
    {
        std::cout << "Constructor" << std::endl;
    }
     ~my_class(void)
    {
        std::cout << "Destructor" << std::endl;
    }
};

my_class& func(void)
{
    my_class* c = new my_class;
    return *c;
}

int main(void)
{
    my_class& var1 = func();
    // Question : I think there is no memory leak.
    // Answer : Yes there is a memory leak in func().
}



/shared/TOOLS/valgrind-3.6.1/bin/valgrind --leak-check=full ./main2.exe
==13004== Memcheck, a memory error detector
==13004== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==13004== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==13004== Command: ./main2.exe
==13004==
Constructor
==13004==
==13004== HEAP SUMMARY:
==13004==     in use at exit: 1 bytes in 1 blocks
==13004==   total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==13004==
==13004== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13004==    at 0x4A06DC7: operator new(unsigned long) (vg_replace_malloc.c:261)
==13004==    by 0x400966: func() (in /home/toto/CppTest/main2.exe)
==13004==    by 0x4009BC: main (in /home/toto/CppTest/main2.exe)
==13004==
==13004== LEAK SUMMARY:
==13004==    definitely lost: 1 bytes in 1 blocks
==13004==    indirectly lost: 0 bytes in 0 blocks
==13004==      possibly lost: 0 bytes in 0 blocks
==13004==    still reachable: 0 bytes in 0 blocks
==13004==         suppressed: 0 bytes in 0 blocks
==13004==
==13004== For counts of detected and suppressed errors, rerun with: -v
==13004== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 7 from 7)


回答5:

You shouldn't replace an owning pointer (one that is responsible for deletion) with a reference; it's idiomatic to assume that references never, ever own the referred resource.

my_class& func1()
{
    my_class* c = new my_class;
    return *c;
}

int main()
{
    my_class& ref = func1();
    // MUST delete, but this is ugly!
    delete &ref;
}

Instead, replace owning pointers by smart pointers: std::unique_ptr func1() { return std::unique_ptr(new my_class); }

int main()
{
    auto p = func1();
    // You gain exception-safety for free
}

You are correct that non-owning pointers can be replaced by references. It is recommended for most cases (see the link at end for more information).

// Won't have to check for 0 in the body
void
my_func1(my_class&);

std::unique_ptr<my_class>
func1()
{
    return std::unique_ptr<my_class>(new my_class);
}

int main()
{
    auto p = func1();

    func2(*p);
}

Here is a question regarding the difference of uses between raw pointers and smart pointers. In an answer of mine I mention difference use cases for raw pointers vs references.