Best way to return newly created object

P

pmatos

Hi all,

Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important. In these
cases I do something like this:

vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

Would there be any other way without pointers?

Would this work:
vector<int>& f() {
vector<int> v;
return v;
}

???

Cheers,

Paulo Matos
 
G

Geo

pmatos said:
Hi all,

Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important. In these
cases I do something like this:

vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

Would there be any other way without pointers?

Would this work:
vector<int>& f() {
vector<int> v;
return v;
}

???

Cheers,

Paulo Matos

No, that won't work, 'v' will be destroyed when 'f' returns, you will
have an invalid reference. You should consider returning a
std::auto_ptr, or some other smart pointer.
 
R

Rolf Magnus

pmatos said:
Hi all,

Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important. In these
cases I do something like this:

vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

Would there be any other way without pointers?

Would this work:
vector<int>& f() {
vector<int> v;
return v;
}

No. Never return a reference to a local object.

What you could do is turn it around. Let the function take the vector as
parameter and fill it:

void f(vector<int>& vec)
{
//fill vec
}
 
T

Torsten Mueller

pmatos said:
vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

I suggest not to return a newly created object. Nobody knows what to
do with the pointer. How it is created? Do we have to delete it? Is it
a pointer on the heap or just an address of an existing object?

Indeed if the function and its caller don't use the same heap
management it could result in a serious problem. This is the case if
you create an object in a DLL and return a pointer up to an
application. If both modules are linked with a static runtime library
the application cannot delete the pointer.

I suggest to create the object outside the function. You can use the
function to fill it.

void f (vector<int>& v)
{
// fill v ...
}

T.M.
 
B

benben

pmatos said:
Hi all,

Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important. In these
cases I do something like this:

vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

Would there be any other way without pointers?

Would this work:
vector<int>& f() {
vector<int> v;
return v;
}

???

Cheers,

Paulo Matos

vector<int> f()
{
return vector<int>;
}

regards,
ben
 
M

Mathias Waack

pmatos said:
Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important. In these
cases I do something like this:

vector<int> * f() {
vector<int> * v = new vector<int>;
return v;
}

Thats usually a wrong way, because calling functions (which means the
programmer of the calling function) usually don't care about data not
created by themself.
Would this work:
vector<int>& f() {
vector<int> v;
return v;
}

Returning a ref to a local object is always wrong. Thinking about your
problem, the question arises:

In the calling function, you can either write:

vector<int> v;
or
vector<int> v = f();

I can't imagine a situation where someone would prefer the second solution.
So I assume you're trying to solve another problem. But without knowing
about it, nobody will be able to help you.

Mathias
 
T

Torsten Mueller

benben said:
vector<int> f()
{
return vector<int>;
}

This will create a copy of the entire vector while the temporary
object will soon be forgotten unless the compiler supports a return
value optimization.

T.M.
 
P

Panjandrum

Torsten said:
This will create a copy of the entire vector while the temporary
object will soon be forgotten unless the compiler supports a return
value optimization.

Even _with_ RVO

vector<int> x = f()

will copy the vector twice.
 
T

Torsten Mueller

Panjandrum said:
Even _with_ RVO

vector<int> x = f()

will copy the vector twice.

I had this in another news group some days ago. Look at the following
program:

#include <iostream>
using namespace std;

struct X
{
X() { cout << "X"; }
X( const X& ) { cout << "C"; }
};

X f()
{
return X();
}

X g()
{
X x;
return x;
}

#define TEST( code ) \
cout << #code << "\t: "; code; cout << endl

int main()
{
TEST( X x1( f() ); );
TEST( X x2( g() ); );
TEST( X const& x3 = f(); );
TEST( X const& x4 = g(); );
}

This little program compiles indeed different with several compilers.
I used the one I had on my machine. Look at this:

------------------------------------------------------------------------
MSVC 6

X x1( f() ); : X
X x2( g() ); : XC
X const& x3 = f(); : X
X const& x4 = g(); : XC
------------------------------------------------------------------------
MSVC 7.1

X x1( f() ); : X
X x2( g() ); : XC
X const& x3 = f(); : X
X const& x4 = g(); : XC
------------------------------------------------------------------------
gcc 3.2.3 (mingw)

X x1( f() ); : X
X x2( g() ); : X
X const& x3 = f(); : X
X const& x4 = g(); : X
------------------------------------------------------------------------
aCC (HP ANSI C++ B3910B A.03.27, HPUX)

X x1( f() ); : XC
X x2( g() ); : XCC
X const& x3 = f(); : X
X const& x4 = g(); : XC
------------------------------------------------------------------------

gcc does never (!) copy. Also the Microsoft compilers do avoid the
copy during return. They copy just the local variable. aCC on HPUX
does indeed copy during return. Because of this differences I would
not use this method of returning an object.

T.M.
 
L

Laurens

Geo said:
You should consider returning a
std::auto_ptr, or some other smart pointer.

I agree with this advice. I recommend using a reference counting pointer
such as boost::shared_ptr for this. This will take care of memory
management automatically.

Regards
-Laurens
 
P

Panjandrum

Torsten said:
gcc does never (!) copy.

The almost empty functions you wrote get inlined. Of course, if an
object is returned it must be copied and then it must be assigned to or
copied into another object (unless you use the returned temporary).
There is no black magic in C++.
Also the Microsoft compilers do avoid the
copy during return.
They copy just the local variable. aCC on HPUX
does indeed copy during return. Because of this differences I would
not use this method of returning an object.

.... and especially not because of a misleading example.
 
R

Rolf Magnus

Panjandrum said:
The almost empty functions you wrote get inlined.

gcc doesn't inline any functions unless optimizations are switched on.
Of course, if an object is returned it must be copied

No, NRVO can optimize that copy away.
and then it must be assigned to or copied into another object (unless you
use the returned temporary).

And also that copy can be optimized away, and gcc can do that.
There is no black magic in C++.

It's not black magic. It's a well-known optimization technique. Instead of
allocating the memory for the object locally in the called function, the
caller provides the memory and passes its address to the called function,
which then constructs the object directly into that memory, and so the
caller can use it without the need to copy it.
 
P

Panjandrum

Rolf said:
Panjandrum wrote:
gcc doesn't inline any functions unless optimizations are switched on.


No, NRVO can optimize that copy away.

No! C and C++ programs consist of a stack of function calls. An object
that is returned to the calling function is copied (even with RVO).
Sorry, I don't have the nerve to argue with you any longer.
 
O

Old Wolf

Panjandrum said:
No! C and C++ programs consist of a stack of function calls. An object
that is returned to the calling function is copied (even with RVO).
Sorry, I don't have the nerve to argue with you any longer.

Sorry, you are talking crap. The GCC result shows that the
object is never copied. If you run the following code, you will
see that the object always has the same address (not surprising
given that it is never copied). The C++ standard says that the
object does not need to be copied. What more evidence do you need?

#include <iostream>
using namespace std;

struct X
{
X() { cout << "X"; }
X( const X& ) { cout << "C"; }
};

X g()
{
X x;
cout << "[" << &x << "]";
return x;
}

#define TEST( code ) \
cout << #code << "\t: "; code; cout << endl

int main()
{
TEST( X x2( g() ); cout << &x2; );
TEST( X const& x4 = g(); cout << &x4; );
}
 
E

E. Robert Tisdale

pmatos said:
Sometimes I have a function which creates an object and returns it.
Some are sets, other vectors but that's not very important.
In these cases I do something like this:

vector<int>* f(void) {
vector<int>* p = new vector<int>;
return p;
}

This is a bad idea.
Would there be any other way without pointers?

Would this work:

vector<int>& f(void) {
vector<int>* p = new vector<int>;
return *p;
}

And so is this.

Simply return by *value*:
> cat f.cc
#include <vector>

std::vector<int> f(void) {
std::vector<int> v;
// modify v
return v;
}

Any decent optimizing C++ compiler will invoke
the Named Return Value Optimization (NRVO) --
the compiler recognizes v as a synonym for the return value
so that *no* copy is required!
 
E

E. Robert Tisdale

Laurens said:
I agree with this advice.

It's bad advice.
I recommend using a reference counting pointer
such as boost::shared_ptr for this.
This will take care of memory management automatically.

Nonsense!
The obvious best solution is to return by *value*.

Reference counting is routinely abused by C++ programmers.
It should be reserved for very special cases.
Objects that contain a reference counter can never truly be constants.
They not *thread safe*
and must be protected by [expensive] mutual exclusion
if they are used in threaded applications.
 
E

E. Robert Tisdale

Torsten said:
I suggest to create the object outside the function.
You can use the function to fill it.

void f(std::vector<int>& v) {
// fill v ...
}

This is a bad idea and it is unnecessary.

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;
}

But the obvious solution here is to return by *value*:

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

Return by value simplifies code

const
std::vector<int> v = f(10);

and allows the application programmers to define constants
instead of compelling them to define variables
and initialize them in a second step.
The Named Return Value Optimization (NRVO)
allows the compiler to initialize v *directly*
from the call to f(10) *without* making any copies!
 
M

Me

vector said:
Even _with_ RVO

vector<int> x = f();

will copy the vector twice.

Wrong. At most it will do 1 default construction, 1 copy, and 2
destructions. With RVO it will just do 1 default construction and 1
destruction.

12.2/1 "Temporaries of class type are created in various contexts: ...
returning an rvalue"
6.6.3/2 "A return statement can involve the construction and copy of a
temporary object (12.2)."
8.5/14 "In certain cases, an implementation is permitted to eliminate
the copying inherent in this direct-initialization by constructing the
intermediate result directly into the object being initialized; see
12.2, 12.8."
12.8/15 "Whenever a temporary class object is copied using a copy
constructor, and this object and the copy have the same cv-unqualified
type, an implementation is permitted to treat the original and the copy
as two different ways of referring to the same object and not perform a
copy at all, even if the class copy constructor or destructor have side
effects."

Then 12.8 goes on to allow NRVO which is even more general than the
above code.
 
A

Amadeus W. M.

It's not black magic. It's a well-known optimization technique. Instead of
allocating the memory for the object locally in the called function, the
caller provides the memory and passes its address to the called function,
which then constructs the object directly into that memory, and so the
caller can use it without the need to copy it.

I wasn't aware of this, and if it's true, I'd certainly like to know more
about it. It'd be a very convenient thing.

You mean this? This I do all the time:

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

int main()
{
vector<int> x(10000000);
x=foobar(x); // of course, = not necessary.
return 0;
}

This is trivial.

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

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

int main()
{
vector<int> x;
x=foobar();
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? That's pretty cool if the
compiler is that smart.

Using g++ 4.0, with -g -Wall. What optimization flags should I use to
avoid the copying? And how about valarray?
 
J

John Smith

pmatos:

consider passing a pointer to a structure which contains every data
type you are in need of, along with a flag in the structure which
indicates which data type has been filled and therefore how to
process...

John
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top