Best way to return newly created object

T

Torsten Mueller

E. Robert Tisdale said:
This is a bad idea and it is unnecessary.

Of course not. It avoids copying safely on *every* compiler.
C++ programmers should avoid functions that modify their arguments
but, if you *must* modify an argument, you should, at least, return
a reference to the modified argument:

std::vector<int>& f(std::vector<int>& v) {
// fill v
return v;
}

Why that? How is the return value related to the modified argument?
And what if there are two?

The only problem I see is to show the caller what's changed and what
is not. And this is just a question of strictly use of "const",
references and pointers in parameters. I use consequently const
references for constant parameters. If it's not const the caller can
be *sure* the parameter will be changed. It's very simple. I don't
understand any confusion about this. Mostly people are just too lazy
to use "const".
But the obvious solution here is to return by *value*:

No, returning by value is not a good idea having large objects and
applications being compiled with different compilers on several
platforms. I have a program on three platforms at the moment. I have
visible speed differences just because of such compiler dependent
stuff.

T.M.
 
A

Amadeus W. M.

Help me understand...


//g++-4.0.
#include <iostream>
#include <cstdlib>
#include <valarray>

using namespace std;

valarray<int> foo(int n)
{
valarray<int> x(n);
cerr << __FUNCTION__ << ": " << __LINE__ << ": "
<< &x << "\t" << x.size() << endl;
return x;
}

int main()
{
valarray<int> x=foo(3000);
valarray<int> y;

y = foo(2000);

cerr << __FUNCTION__ << ": " << __LINE__ << ": "
<< &x << "\t" << x.size() << endl;

cerr << __FUNCTION__ << ": " << __LINE__ << ": "
<< &y << "\t" << y.size() << endl;

return 0;
}
 
R

Rolf Magnus

Amadeus said:
Help me understand...


//g++-4.0.
#include <iostream>
#include <cstdlib>
#include <valarray>

using namespace std;

valarray<int> foo(int n)
{
valarray<int> x(n);
cerr << __FUNCTION__ << ": " << __LINE__ << ": "
<< &x << "\t" << x.size() << endl;
return x;
}

int main()
{
valarray<int> x=foo(3000);

This is copy construction.
valarray<int> y;

y = foo(2000);

This is copy assignment, which can not be optimized away.
 
E

E. Robert Tisdale

Amadeus said:
I wasn't aware of this and, if it's true,
I'd certainly like to know more about it.

I used Google

http://www.google.com/

to search for

+"C++" +"NRVO"

and I found lots of stuff.
It'd be a very convenient thing.

You mean this? This I do all the time:

std::vector<int>& foobar(std::vector<int> & x) {
// do stuff to x
return x;
}

int main(int argc, char* argv[]) {
vector<int> x(10000000);
// x=foobar(x); // of course, = not necessary.
foobar(x); // It's wrong.
return 0;
}

This is trivial.

Or you mean it's all done transparently to the caller?

vector<int> foobar(void) {
vector<int> x(10000000);
// do stuff to x
return x;
}

int main(int argc, char* argv[]) {
vector<int> x = foobar();
// Use the copy constructor and *not* the assignment operator.
// The optimizer can elide the copy constructor
// but *not* the assignment operator.
return 0;
}

This indeed looks like voodoo.
The vector::eek:perator=() allocates the necessary memory
and it does work with vector (I checked)
but it certainly doesn't work with valarray.
You mean the compiler does all the magic behind the scenes:
it notices main::x will be allocated memory
and that foo::x will no longer be needed
after it's returned and assigned to x
so it might as well use the same memory?

You are confused.
You must avoid the assignment operator
and use the copy constructor instead.
That's pretty cool if the compiler is that smart.

All quality C++ compilers are that smart.
If your compiler does not implement the NRVO,
you should be shopping for a new C++ compiler
that does implement the NRVO.
Using g++ 4.0 with -g -Wall,

g++ -Wall -ansi -pedantic

Don't use the -g option unless you need to use the debugger.
What optimization flags should I use to avoid the copying?
And how about valarray?

The GNU C++ compiler, g++,
implements the Named Return Value Optimization (NRVO) by default.
 
E

E. Robert Tisdale

Torsten said:
E. Robert Tisdale schrieb:



Of course not. It avoids copying safely on *every* compiler.


Why that? How is the return value related to the modified argument?
And what if there are two?

I have just told you that
functions should *not* modify their arguments.
That goes double for two arguments. :)

There are some exceptions
where operations must be performed "in place" on a variable object
but there is seldom any excuse for returning void.
You should always return something -- an exception (error code)
or a reference to the the object that was modified if nothing else.
This is a long standing tradition in C and C++.
Consider, for example, strcpy(char*, const char*)
which returns a pointer to the destination string or
operator<<(std::eek:stream&, int) which returns a reference
to the output stream which it modifies.
The only problem [that] I see
is to show the caller what's changed and what is not.
And this is just a question of strictly use of "const",
references and pointers in parameters.
Consequently, I use const references for constant parameters.
If it's not const the caller can be *sure* the parameter will be changed.
It's very simple.
I don't understand any confusion about this.
Mostly people are just too lazy to use "const".
But the obvious solution here is to return by *value*:

No, returning by value is not a good idea
[if you have] large objects and applications
being compiled with different compilers on several platforms.
I have a program on three platforms at the moment.
I have visible speed differences
just because of such compiler dependent stuff.

Using a bad C++ compiler is *not* a good excuse
for writing bad C++ code.
If your C++ compiler does not implement
the Named Return Value Optimization (NRVO),
you should be shopping for a new C++ compiler
that *does* implement the NRVO.

The market place is highly competitive
and quality implementations are available almost everywhere.
Inferior implementations should be discarded not coddled.
 
A

Amadeus W. M.

I used Google
http://www.google.com/

to search for

+"C++" +"NRVO"

Funny. Ponder about your recommendation for a minute: how could I have
used google on something whose existence was not known to me? I did after
I read about it in this thread, of course.
You are confused.
You must avoid the assignment operator
and use the copy constructor instead.

Is this a commandment coming from a rocket scientist? Your advice is good,
and I don't mean any disrespect, but it would be better received if you
didn't speak in such a dismissive tone. People need to understand why, not
to be ordered.

And as a matter of fact, I know the constructor should be used and not the
assignment. However, constructing objects only upon the point when they
are needed (and parameters known), as opposed to declaring/constructing
them at the beginning of the function, confuses gdb, more often than not.

g++ -Wall -ansi -pedantic

Don't use the -g option unless you need to use the debugger.

But I do. Doesn't everyone?
The GNU C++ compiler, g++,
implements the Named Return Value Optimization (NRVO) by default.

I figured, thanks!

Now NRVO works with the copy constructor only, and not with assignment. I
see no mention in the original post saying that he was going to use it
with the copy constructor. You're recommending something less general than
the scope of the original question, without even a warning, other than
"it's bad".

I realize that I've completely undermined my chances of ever working at
NASA.
 
E

E. Robert Tisdale

Amadeus said:
But I do. Doesn't everyone?

I never use the debugger on code that I wrote.
I sometimes find it useful for analyzing code that other people wrote.
I figured, thanks!

Now NRVO works with the copy constructor only, and not with assignment.
I see no mention in the original post
saying that he was going to use it with the copy constructor.
You're recommending something less general than the scope of the original question
without even a warning, other than "it's bad".

This:

int main(int argc, char* argv[]) {
vector<int> x;
x = foobar();
return 0;
}

is bad. This:

int main(int argc, char* argv[]) {
vector<int> x = foobar();
return 0;
}

is better. And this:

int main(int argc, char* argv[]) {
const
vector<int> x = foobar();
return 0;
}

is better yet if you don't need to modify x in your program.
In general, you should avoid unnecessary program state variables
because they make your program more difficult to analyze
(read, understand and maintain).
 
G

Geo

E. Robert Tisdale said:
Using a bad C++ compiler is *not* a good excuse
for writing bad C++ code.
If your C++ compiler does not implement
the Named Return Value Optimization (NRVO),
you should be shopping for a new C++ compiler
that *does* implement the NRVO.

The market place is highly competitive
and quality implementations are available almost everywhere.
Inferior implementations should be discarded not coddled.

I guess working at NASA is similar to not living in the real world, I
would bet that most of us just don't have that choice.
 
T

Torsten Mueller

E. Robert Tisdale said:
There are some exceptions where operations must be performed "in
place" on a variable object but there is seldom any excuse for
returning void.

What a beautiful dogma. Why that? It's just my decision to return
something or not.
You should always return something -- an exception (error code) or a
reference to the the object that was modified if nothing else. This
is a long standing tradition in C and C++.

Tradition is also to use int or char instead of bool.
Consider, for example, strcpy(char*, const char*) which returns a
pointer to the destination string or operator<<(std::eek:stream&, int)
which returns a reference to the output stream which it modifies.

These return values are for concatenation of multiple following
operations. They are useful.

I have a library of special string functions based on the STL string
class. These functions always return a string object. Nobody asks for
the time needed to create these temporary objects but everyone wonders
"It's not very fast, isn't it?". Nobody thinks about heap
fragmentation. Until now I eliminated more than two millions of
absolutely senseless string objects created in just one single minute
of runtime. Tell me, is this paradigma ("always return something")
useful in this case?

There is a lot of situations where indeed no result is to return,
where no result exists, where it needs just more time to create and to
evaluate the result than to return just nothing. Why the hell should a
sleep-function return something? And what?
Using a bad C++ compiler is *not* a good excuse for writing bad C++
code.

You can really be proud on you for knowing the bad and the good things
in the world. Have you ever been working on a system with a *given*
compiler, a compiler that cannot be changed for several reasons, a
compiler you just have to live with, and a manager who wants still a
good program?
If your C++ compiler does not implement the Named Return Value
Optimization (NRVO), you should be shopping for a new C++ compiler
that *does* implement the NRVO.

As long as I know how the compiler works and what I have to do to
write a quality program, a readable one, a fast one, a program that
runs on *any* compiler, I will do this. This is my profession. And my
profession is also to know these things rather than to assume every
compiler will surely do it right and fast.

I think it's not always a bad idea to change function parameters
especially if there are more than one. I use it seldom but sometimes
everything else would be just more complicated. I always mention it in
a comment. I name the function in that way

bool GetLoginValues (string& uid,string& pwd,string& host);

And I strictly use "const" for everything that *is* const. There's
nothing evil.

T.M.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top