3

I'm in front of this and will have to deal with C++98, possibly C++03, and C++11 :

type1 myfunc( type2& var = /*some value of type "type2"*/ )
{
   // Some code
}

I tried this :

type1 myfunc( type2& var = *(new type2) )
{
   // Some code
}

And of course it works, but I'm not sure wether this creates or not a memory leak. What does this code exacty do in the computer memory ? If I can't do this, do I have any other solutions than to overload my function?

max66
  • 65,235
  • 10
  • 71
  • 111
  • 6
    Take const ref if you can, that'd allow you to take a temporary. If you can't, take a global variable as default param. If you can't, take an optional<> ref as input. – lorro Jun 26 '16 at 15:07
  • 4
    Make an overload, don't allocate anything. See [this](http://stackoverflow.com/questions/1059630/default-value-to-a-parameter-while-passing-by-reference-in-c). Of course it's leaking. – LogicStuff Jun 26 '16 at 15:07
  • More on const references [here](http://stackoverflow.com/q/2784262/1460794) – wally Jun 26 '16 at 15:13
  • 1
    Yes. It leaks memory. – Jesper Juhl Jun 26 '16 at 15:16
  • Maybe rvalue reference would suit your needs? `type1 myfunc( type2&& var = type2() ) { /*... */ }` – W.F. Jun 26 '16 at 15:29

3 Answers3

3

The question is tagged C++11, so I suppose you can use std::unique_ptr to solve this problem.

A little example

#include <memory>
#include <iostream>

std::size_t myfunc( std::string const & var
   = * std::unique_ptr<std::string>(new std::string("default string")) )
{ return var.size(); }

int main ()
 {
   std::cout << "default:  " << myfunc() << std::endl;
   std::cout << "argument: " << myfunc("no default") << std::endl;

   return 0;
 }

Hoping this helps.

--- added C++98/C++03 solution ---

Isn't clear what language the OP want to use.

In case of C++98/C++03, it's possible to use std::auto_ptr instead of the C++11 std::unique_ptr.

I remember that std::auto_ptr is deprecated from C++11, so use it only if you can't use C++11 (or a newer standard)

The following example should be C++98 compliant (I've removed the const too)

#include <memory>
#include <iostream>

std::size_t myfunc(std::string & var
   = * std::auto_ptr<std::string>(new std::string("default string")) )
{ return var.size(); }

int main ()
 {
   std::string noDef("no default");

   std::cout << "default:  " << myfunc() << std::endl;
   std::cout << "argument: " << myfunc(noDef) << std::endl;

   return 0;
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • @BenjaminLindley - are you sure? – max66 Jun 26 '16 at 15:31
  • @NicolBolas: You sure? According to my example, this also works with non-const reference (not saying it is a particular good solution) – MikeMB Jun 26 '16 at 15:37
  • 2
    @max66: No, my mistake. I forgot that the initialization expression happens within the context of the calling function. – Benjamin Lindley Jun 26 '16 at 15:38
  • @NicolBolas - I've tryed a test similar to the one of MikeMB and, even without const, the destruction of my test class is at the end of the function. – max66 Jun 26 '16 at 15:40
  • @all - sorry for my bad English – max66 Jun 26 '16 at 15:43
  • @BenjaminLindley - more I study C++11, more I think it'a a nightmare to understand how it exactly work; thanks to help me to understand – max66 Jun 26 '16 at 15:45
  • 1
    If this could be proven to be a reliable solution without const then it would be very interesting. I'm curious to learn what the standard says about the lifetime of objects declared this way. – wally Jun 26 '16 at 15:46
  • @flatmouse - +1: I'm curious too. – max66 Jun 26 '16 at 15:51
  • @flatmouse: I don't see the problem: The temporary unique_ptr instance lives until the end of the expression containing the call to myfunc and by extension, the same is true for the object managed by it. The question if the reference is const or not is completely irrelevant for this - either it works for both or for none. – MikeMB Jun 26 '16 at 16:15
  • My bad, I mistakenly added "C++11" instead of "C++0x", but thank you for your answer ! –  Jun 26 '16 at 17:48
  • @cylgom - if I'm not wrong, "C++0x" is the old identifier for "C++11"; but, exactly, what language are you using? – max66 Jun 26 '16 at 17:56
  • @cylgom - I've modified my answer adding a solution C++98/C++03 compliant (but deprecated for C++11/C++14/...); but I renew my question: exactly, which version of the C++ standard are you using? – max66 Jun 26 '16 at 18:20
  • @max66 owwww I didn't know that. Sorry for the confusion. C++11 was ok then –  Jun 26 '16 at 18:22
  • @max66 I'm glad you added solutions for all versions, this is perfect. Thank you. –  Jun 26 '16 at 18:25
3

If you allocate memory and don't delete it you have a memory leak, regardless of the shenanigans you pull with dereferencing, references, or pointer manipulations.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
2

This code will create a memory leak in situations when the default parameter is used, unless myfunc frees it (which would be a hack):

type1 myfunc( type2& var = *(new type2) ) {
   // Some code
   delete &var; // Very bad, don't do it like that.
}

When the call is made with a parameter specified for the var, there would be no memory leak without the delete. This is because the compiler sees that you are passing an argument for the reference parameter, and not allocate new type2.

One approach to create a default reference without making a memory leak is to define a static throw-away variable, and use it as a reference:

static type2 throwaway;
type1 myfunc( type2& var = throwaway ) {
    // Some code
}

This way the callers who do not need to see modifications done to var would be able to call your function without specifying a reference for it. Of course if myfunc makes any modifications to var, the callers would not be able to see them.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523