13

I am just learning C++, and I've come across the following conundrum:

As a C++ newbie, I've read that using reference instead of pointers (when possible) is generally a good idea, so I'm trying to get into the habit early. As a result, I have a lot of methods which have the general form of

void myMethod(ParamClass const& param);

Now, I'm wondering what is the best way to call these methods. Of course, each call will need a different object passed as a parameter, and as far as I know the only way to create it is the new operator, so now I'm doing the following:

myObject.myMethod(*new ParamClass(...));

While this method totally works, I'm wondering if there isn't another already-established "c++ way" of doing this.

Thanks for the help! Dan

Dan Nestor
  • 2,441
  • 1
  • 24
  • 45
  • 3
    doing that, you are leaking memory, because you will never hold the pointer value anywhere. – Benoit Feb 01 '11 at 13:49
  • The book, "C++ GUI Programming with Qt 4", has an excellent appendix called, "Introduction to C++ for Java and C# Programmers." If that is the background from which you are coming, it would probably provide an efficient "quick start" for changing some of your established patterns between the languages. Most libraries can get a copy using ILL if you don't want to purchase the book. (If you are considering using Qt, though, *get the book*. – Dave Mateer Feb 01 '11 at 13:57

6 Answers6

14

You should try not to use new, to begin with, as using it brings the trouble of memory management.

For your example, just do the following:

int main(int, char*[])
{
  SomeObject myObject;

  // two phases
  ParamClass foo(...);
  myObject.myMethod(foo);

  // one phase
  myObject.myMethod(ParamClass(...));

  return 0;
}

I recommend the first method (in two times) because there are subtle gotchas with the second.

EDIT: comments are not really appropriate to describe the gotchas I was referring to.

As @Fred Nurk cited, the standard says a few things about the lifetime of temporaries:

[class.temporary]

(3) Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.

(5) The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference [note: except in a number of cases...]

(5) [such as...] A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.

This can lead to two subtle bugs, that most compilers do not catch:

Type const& bound_bug()
{
  Type const& t = Type(); // binds Type() to t, lifetime extended to that of t
  return t;
} // t is destroyed, we've returned a reference to an object that does not exist

Type const& forwarder(Type const& t) { return t; }

void full_expression_bug()
{
  T const& screwed = forwarder(T()); // T() lifetime ends with `;`
  screwed.method(); // we are using a reference to ????
}

Argyrios patched up Clang at my request so that it detects the first case (and a few more actually that I had not initially thought of). However the second can be very difficult to evaluate if the implementation of forwarder is not inline.

Community
  • 1
  • 1
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    What "subtle gotchas" are you referring to? Sounds like FUD to me. – Cheers and hth. - Alf Feb 01 '11 at 13:59
  • 1
    @Alf: I wish... try passing a bound temporary to `T const& foo(T const& t) { return t; }`, it's really amusing :/ Bound temporaries are a mine-field for the unwary, and compilers are out of their depth when it comes to diagnose this. – Matthieu M. Feb 01 '11 at 14:02
  • 1
    @Matthiu: now it's openly and clearly pure FUD, as far as I'm concerned. there's no such thing as a "bound temporary". perhaps you mean a temporary bound to a reference, in which case it's the same as passing a variable (it's indistinguishable). – Cheers and hth. - Alf Feb 01 '11 at 14:05
  • 1
    Thanks everybody for their answers. – Dan Nestor Feb 01 '11 at 14:11
  • @Alf: Think a bit more (or look through the questions I ask) the lifetime of the temporary is extended up until the lifetime of the reference it's bound to (that is, in this case, for the duration of the function). But then we are returning this reference, therefore the caller of `foo` gets a reference to a temporary whose existence has ceased. Isn't it wonderful ? Provokes a nice core-dump on my computer (when I am lucky). – Matthieu M. Feb 01 '11 at 14:12
  • @Matthieu: shouldn't that function you described simply return the same reference that was passed to it? – Dan Nestor Feb 01 '11 at 14:12
  • @AlfP.Steinbach: I suspect Matthieu is referring to unspecified argument evaluation order which is very significant when parameters depend on each other. This dependence is most famously illustrated when it is implicit: `f(new int(), new int())`. (I'm sure you're aware of this and have seen the GotW article, so I won't search for the link.) – Fred Nurk Feb 01 '11 at 14:13
  • @dandrestor: if you are talking about the comments, I suggest you pay no attention to it for the moment, it's one of C++ dark corners. – Matthieu M. Feb 01 '11 at 14:14
  • @MatthieuM.: No, the lifetime of temporaries is *not* the lifetime of a reference bound to them, except in one special case. When passed as a parameter, temporaries live until the end of the full expression in which they are created. – Fred Nurk Feb 01 '11 at 14:14
  • @Fred Nurk: if @Matthieu was referring to dependency problems then he didn't say so, but instead said something else. Anyway, named variables can solve that but is not how to pass arguments in general. So, I've now downvoted this answer (it's a shame that bad and even in some cases incorrect answers so often are selected as solution). – Cheers and hth. - Alf Feb 01 '11 at 14:18
  • @Fred, @Alf: I guess I should really work on my wording... Anyway, consider `T const& super = foo(T());`, this is valid code, but once the expression has been evaluated, what is `super` referencing ? – Matthieu M. Feb 01 '11 at 14:18
  • 1
    @AlfP.Steinbach: He was vague, but I see no reason that seriously detracts from the answer. It's certainly not bad nor incorrect. – Fred Nurk Feb 01 '11 at 14:20
  • @Matthiu: you're referring to lifetime issues. they are the same for temporaries and local variables: the lifetime of an object must be sufficient. it does not help to introduce variables for someone who is not aware of this. rather, it just messes up the code. i've downvoted your answer now because it promotes ungood practice *and* because of the FUD -- we really need less of that! Cheers, – Cheers and hth. - Alf Feb 01 '11 at 14:21
  • @MatthieuM.: That's tangential to this question, as the given method returns void. It is true that super is invalid if foo returns its parameter, but you'd have a worse answer listing every caveat of references without some indication that they even apply. – Fred Nurk Feb 01 '11 at 14:21
  • @Fred: I agree it's tangential, and that is why I (originally) chose to remain vague. It's just that I am sensitive to this bug because it blew up the server I am working on and it really took some time to track it down. – Matthieu M. Feb 01 '11 at 14:28
  • @Alf: I understand the downvote, no worry, it's true that object lifetime is a difficult subject (in C++) and that a beginner might screw up in either case (and not only a beginner...) – Matthieu M. Feb 01 '11 at 14:30
  • @MatthieuM.: What you list in the edit isn't exactly correct. You'd probably be better off finding and linking to a good question about it than re-inventing it here. – Fred Nurk Feb 01 '11 at 14:32
  • @Fred: this one http://stackoverflow.com/questions/4721841/whats-the-point-of-temporary-bound-to-a-member-lifetime-statement-in-c-standar/4721954#4721954 for example :) ? I am interested in the "incorrect" bit, even though tangential, I might as well go all the way now. – Matthieu M. Feb 01 '11 at 14:35
  • @MatthieuM.: That answer is only about binding to reference members in the ctor initializer, which is very rare. "It is extended if the temporary is bound to a const reference" is too broad; const-ref parameters need to be explicitly excluded. The lifetime isn't "extended" until the end of the full expression: that *is* the normal lifetime. That's the two bits I spoke of, and I didn't scan the rest. – Fred Nurk Feb 01 '11 at 14:40
  • @Matthieu In your first code snippet, when using the two-phase method, wouldn't object foo go out of scope at the end of main()? Suppose then I am not calling myMethod from main, but some other function. Is it safe to do this, if I want to store foo somewhere inside my SomeObject class and use it at a later time? – Dan Nestor Feb 01 '11 at 14:41
  • @dandrestor: That sounds like something best packaged up as a complete test case and asked as its own question. – Fred Nurk Feb 01 '11 at 14:45
  • http://stackoverflow.com/questions/4864022/reference-parameter-lifetime , if anybody would like to chip in there as well. Thanks! – Dan Nestor Feb 01 '11 at 14:55
  • @Mattieu: with your edit I now understand what you meant by "bound temporary". and it is indeed as I assumed you meant then, a temporary bound to a reference. note that this is *exactly the same* as returning a reference to a local variable. – Cheers and hth. - Alf Feb 01 '11 at 15:07
  • @Alf: Sorry for my difficulties in explaining it, I struggle a bit between English and "Standard" language :/ – Matthieu M. Feb 01 '11 at 15:16
  • What if you need to call the constructor of the class? New is a convenient way to make sure this happens without additional fudging. – Stradigos Jan 10 '15 at 06:00
  • @Stradigos: I simply do not understand what you are talking about; `myObject.myMethod(ParamClass(...));` evidently call one of the constructors of `ParamClass` and there is no `new`... – Matthieu M. Jan 10 '15 at 12:05
3

Try: myObject.myMethod(ParamClass(...)); in C++, unlike Java, you do not always need to say new to create a new object.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
1

The established way of doing it is with an automatic local variable:

ParamClass myParam;
myOjbect.myMethod(myParam);

By using new in the way you did, you're generating a memory leak. Nothing will dispose of that object once the function returns - C++ does not have garbage collection as some other languages do.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

Just note that there is big difference between assigning the value of an object (I mean the object of the user defined class) previously created to new object in java and c++ , and it is about :

1- in C++ : object new =(object) older [ create a copy of the object older to newer and when you modify newer ,the older will not change !]

2- in java : object new =(object) older [create a reference to the older object and when you modify the newer , the older also will change (very very important)]

conclusion :

in java : "object new =(object) older" is the same as "object &new =(object) older" in c++.

Infintyyy
  • 929
  • 1
  • 11
  • 23
0

You need to be aware of the lifetime of the object. If you pass *new ParamClass to a function, you're giving ownership of the new object to the function. If the function does not destroy it (and it should never do that given a reference), you'll get a memory leak.

Instead, you should do something like this:

ParamClass myParamClass(...);
myObject.myMethod(myParamClass);
Frederik Slijkerman
  • 6,471
  • 28
  • 39
0

When you write

myObject.myMethod(*new ParamClass(...)); 

you lose the pointer to the new'd object. That is, this will work, but you won't be able to later delete the object. So you can do this:

ParamClass pc(...);
myObject.myMethod(pc);

or, easier

myObject.myMethod(ParamClass(...));

or, if dynamic allocation is necessary for some inexplicable reason

ParamClass* pPc = new ParamClass(...);
myObject.myMethod(*pPc);
...
delete pPc;

or, use smart pointers to avoid manual deletion. Something like:

boost::scoped_ptr<ParamClass> spPc(new ParamClass(...));
myObject.myMethod(*pPc);

Hope this helps

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434