how to return std::vector from function?

Z

zl2k

hi, c++ user

Suppose I constructed a large array and put it in the std::vector in a
function and now I want to return it back to where the function is called.
I can do like this:

std::vector<int> fun(){
//build the vector v;
return v;
}

int main(){
std::vector<int> a = fun();
return 0;
}

It works fine. However, I believe there is a deep copy in fun(), so the
cost is big when the array is big. Now I tried to return a pointer without
deep copy.

std::vector<int>* fun(){
//build a pointer to vector;
return *v;
}

int main(){
std::vector<int>* a = fun();
return 0;
}

This got memory leak trouble in fun() since v will be deleted after return
thus the pointer returned will be invalid.

Is there anyway that I can get a correct pointer from fun()? I also
thought to use a smart pointer, such as boost::shared_ptr:

boost::shared_ptr< std::vector<int> > getV(){
boost::shared_ptr< std::vector<int> > v;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}

I got the following message when run the program:
/usr/include/boost/shared_ptr.hpp:253: T* boost::shared_ptr<T>::eek:perator->() const [with T = std::vector<int, std::allocator<int> >]: Assertion `px != 0' failed.
Aborted

How can I get it correct? Is there any deep copy when the getV() return
the shared_ptr?

Thanks a lot.

zl2k
 
R

Rolf Magnus

zl2k said:
hi, c++ user

Suppose I constructed a large array and put it in the std::vector in a
function and now I want to return it back to where the function is called.
I can do like this:

std::vector<int> fun(){
//build the vector v;
return v;
}

int main(){
std::vector<int> a = fun();
return 0;
}

It works fine. However, I believe there is a deep copy in fun(),
Why?

so the cost is big when the array is big. Now I tried to return a pointer
without deep copy.

std::vector<int>* fun(){
//build a pointer to vector;
return *v;
}

int main(){
std::vector<int>* a = fun();
return 0;
}

This got memory leak trouble in fun() since v will be deleted after return
thus the pointer returned will be invalid.

Your description is correct, though that is not a memory leak.
Is there anyway that I can get a correct pointer from fun()? I also
thought to use a smart pointer, such as boost::shared_ptr:

boost::shared_ptr< std::vector<int> > getV(){
boost::shared_ptr< std::vector<int> > v;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}

I got the following message when run the program:
/usr/include/boost/shared_ptr.hpp:253: T*
boost::shared_ptr<T>::eek:perator->() const [with T = std::vector<int,
std::allocator<int> >]: Assertion `px != 0' failed. Aborted

How can I get it correct? Is there any deep copy when the getV() return
the shared_ptr?

Instead of returning a vector, your function could simply take one by
reference.

void fun(std::vector<int>& v){
//fill the vector v;
}

int main(){
std::vector<int> a;
fun(a);
return 0;
}
 
B

BigBrian

std::vector said:
//build a pointer to vector;
return *v;

do you mean

return &v;

?
}

int main(){
std::vector<int>* a = fun();
return 0;
}

This got memory leak trouble in fun() since v will be deleted after return
thus the pointer returned will be invalid.

It's not a memory leak, you have a pointer to an object on the stack
that's not there anymore.
Is there anyway that I can get a correct pointer from fun()?

you could do something like this...

std::vector<int>* fun()
{
std::vector<int> * v = new std::vector<int>();
//build *v;
return v;
}

and then make sure the caller deletes the returned value.

or you could do something like this...

void fun( std::vector<int> & v )
{
// build v;
}

int main()
{
std::vector<int> x;
fun(x);
}

-Brian
 
L

loufoque

zl2k wrote :
Suppose I constructed a large array and put it in the std::vector in a
function and now I want to return it back to where the function is called.
I can do like this:

std::vector<int> fun(){
//build the vector v;
return v;
}

int main(){
std::vector<int> a = fun();
return 0;
}

It works fine.

This is indeed the correct way to do it.

However, I believe there is a deep copy in fun(), so the
cost is big when the array is big.

There won't be any copy if the compiler is smart enough.
There are well known optimizations for return values to prevent
unnecessary copies.

Now I tried to return a pointer without
deep copy.

Using pointers here will only make it messy.
 
Z

zl2k

I am not sure, correct me if not. Is there any deep copy needed if I
return a std container from a function? I'll be very happy if not.
Your description is correct, though that is not a memory leak.
right, no leak but the returned pointer is invalid.
Is there anyway that I can get a correct pointer from fun()? I also
thought to use a smart pointer, such as boost::shared_ptr:

boost::shared_ptr< std::vector<int> > getV(){ boost::shared_ptr<
std::vector<int> > v; v->push_back(1); v->push_back(2); return v;
}
}
int main(){
boost::shared_ptr< std::vector<int> > v = getV(); std::cout <<
v->at(0);
return 0;
}
}
I got the following message when run the program:
/usr/include/boost/shared_ptr.hpp:253: T*
boost::shared_ptr<T>::eek:perator->() const [with T = std::vector<int,
std::allocator<int> >]: Assertion `px != 0' failed. Aborted

How can I get it correct? Is there any deep copy when the getV() return
the shared_ptr?

Instead of returning a vector, your function could simply take one by
reference.

void fun(std::vector<int>& v){
//fill the vector v;
}
}
int main(){
std::vector<int> a;
fun(a);
return 0;
}
In some cases, I can't construct an empty container and pass it to the
function. I want the class which owns the member function fun to own the
container. Say,

Class A {
public:
void GenerateBigData();
void getBigData();
private:
std::vector<int> bigData;
}

Basically, the bigData is generated within the class A. When I need it, I
just want to access the bigData by calling getBigData. I don't want a
duplicated copy of the bigData, a reference will be good. I don't know how
to implement it.

zl2k
 
B

BigBrian

loufoque said:
zl2k wrote :


This is indeed the correct way to do it.



There won't be any copy if the compiler is smart enough.
There are well known optimizations for return values to prevent
unnecessary copies.



Using pointers here will only make it messy.

That may be, but then if performance is an issue, you won't have to
assume that your compiler is smart enough to optimize. IMHO, passing
the array into the function in by reference makes the most since.
 
M

Matthias Kluwe

Hi!

zl2k said:
In some cases, I can't construct an empty container and pass it to the
function. I want the class which owns the member function fun to own the
container. Say,

Class A {
public:
void GenerateBigData();
void getBigData();
private:
std::vector<int> bigData;
}

Basically, the bigData is generated within the class A. When I need it, I
just want to access the bigData by calling getBigData. I don't want a
duplicated copy of the bigData, a reference will be good. I don't know how
to implement it.

If you find a reference acceptable, why not let getBigData return a const reference to bigData?

Regards,
Matthias
 
C

Clark S. Cox III

Is there anyway that I can get a correct pointer from fun()? I also
thought to use a smart pointer, such as boost::shared_ptr:

boost::shared_ptr< std::vector<int> > getV(){
boost::shared_ptr< std::vector<int> > v;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}

I got the following message when run the program:
/usr/include/boost/shared_ptr.hpp:253: T*
boost::shared_ptr<T>::eek:perator->() const [with T = std::vector<int,
std::allocator<int> >]: Assertion `px != 0' failed.
Aborted

Your code is essentially right, save for one thing: You never set the
pointer to point at anything; i.e. it is a default constructed NULL
shared_ptr. Try this instead:

boost::shared_ptr< std::vector<int> > getV(){
//Note the 'new' on the next line, as it is what actually creates the vector
boost::shared_ptr< std::vector<int> > v = new std::vector<int>;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}
 
T

Tomás

Suppose I constructed a large array and put it in the std::vector in a
function and now I want to return it back to where the function is
called.


#include <vector>

template <class T>
class Unconstructed
{
private:

union UniversalAllignment
{
char a; int b; short c; long d;

bool e;

float f; double g; long double h;

void* p;
};

UniversalAllignment buffer[
sizeof(T) / sizeof(UniversalAllignment)
+ static_cast<bool>( sizeof(T) % sizeof(UniversalAllignment) )
];

public:

void* ObjectAddress()
{
return &buffer;
}

T& GetProperReference()
{
return *static_cast<T*>( ObjectAddress() );
}

};

void fun(void* p)
{
new(p) std::vector<int>();
}


int main()
{
Unconstructed< std::vector<unsigned> > my_vec;

fun( my_vec.ObjectAddress() );

std::vector<unsigned>& real_vec = my_vec.GetProperReference();

real_vec.push_back( 5 );

real_vec.~vector();
}


-Tomás
 
L

loufoque

BigBrian a écrit :
That may be, but then if performance is an issue, you won't have to
assume that your compiler is smart enough to optimize.

If performance is an issue, use a performant compiler, that will indeed
optimize correctly.

It's a waste of time trying the write fast code with a compiler that
doesn't translate C/C++ code into the most efficient machine code it could.
 
R

Roland Pibinger

BigBrian a écrit :


If performance is an issue, use a performant compiler, that will indeed
optimize correctly.

What would you do with the returned temporary vector? Assign it to
another vector?

Regards,
Roland Pibinger
 
B

BigBrian

loufoque said:
BigBrian a écrit :


If performance is an issue, use a performant compiler, that will indeed
optimize correctly.

It's a waste of time trying the write fast code with a compiler that
doesn't translate C/C++ code into the most efficient machine code it could.

I disagree, especially in this case. Why return a huge object by value
and just hope the compiler does the optimization, when there are other
options that are just as easy to implement and then you *know* you
won't have this as a performance issue.

Also, using a different compiler isn't always an option.

-Brian
 
Z

zl2k

do you mean

return &v;

?


It's not a memory leak, you have a pointer to an object on the stack
that's not there anymore.


you could do something like this...

std::vector<int>* fun()
{
std::vector<int> * v = new std::vector<int>();
//build *v;
return v;
}
This has the same problem as mine: the v is lost after fun() is called and
the returned pointer is invalid.
and then make sure the caller deletes the returned value.

or you could do something like this...

void fun( std::vector<int> & v )
{
// build v;
}
}
int main()
{
std::vector<int> x;
fun(x);
}
}
-Brian
This works but for some reason I can't transfer an empty vector to the fun
and before the fun is called.
 
Z

zl2k

Hi!

zl2k said:
In some cases, I can't construct an empty container and pass it to the
function. I want the class which owns the member function fun to own the
container. Say,

Class A {
public:
void GenerateBigData();
void getBigData();
private:
std::vector<int> bigData;
}

Basically, the bigData is generated within the class A. When I need it, I
just want to access the bigData by calling getBigData. I don't want a
duplicated copy of the bigData, a reference will be good. I don't know how
to implement it.

If you find a reference acceptable, why not let getBigData return a const reference to bigData?

Regards,
Matthias

how to do that?
 
Z

zl2k

Is there anyway that I can get a correct pointer from fun()? I also
thought to use a smart pointer, such as boost::shared_ptr:

boost::shared_ptr< std::vector<int> > getV(){
boost::shared_ptr< std::vector<int> > v;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}

I got the following message when run the program:
/usr/include/boost/shared_ptr.hpp:253: T*
boost::shared_ptr<T>::eek:perator->() const [with T = std::vector<int,
std::allocator<int> >]: Assertion `px != 0' failed.
Aborted

Your code is essentially right, save for one thing: You never set the
pointer to point at anything; i.e. it is a default constructed NULL
shared_ptr. Try this instead:

boost::shared_ptr< std::vector<int> > getV(){
//Note the 'new' on the next line, as it is what actually creates the vector
boost::shared_ptr< std::vector<int> > v = new std::vector<int>;
v->push_back(1);
v->push_back(2);
return v;
}

int main(){
boost::shared_ptr< std::vector<int> > v = getV();
std::cout << v->at(0);
return 0;
}

It looks good, but can I sure that there is no deep copy involved when
getV() is called?
 
Z

zl2k

I disagree, especially in this case. Why return a huge object by value
and just hope the compiler does the optimization, when there are other
options that are just as easy to implement and then you *know* you
won't have this as a performance issue.

Also, using a different compiler isn't always an option.

-Brian

So what is the straight forward way to solve the problem (without passing
an empty container into the fun and porpulize it inside)?
 
M

Marcus Kwok

zl2k said:
This has the same problem as mine: the v is lost after fun() is called and
the returned pointer is invalid.

Not quite. The v is lost after fun() is called, but the memory
pointed-to by v is still there and valid since it was allocated
dynamically on the heap, as opposed to on the stack. Then, returning a
pointer to this memory is OK, since it will exist longer than the
lifetime of fun().
 
M

Marcus Kwok

Marcus Kwok said:
Not quite. The v is lost after fun() is called, but the memory
pointed-to by v is still there and valid since it was allocated
dynamically on the heap, as opposed to on the stack. Then, returning a
pointer to this memory is OK, since it will exist longer than the
lifetime of fun().

I should add that the caller of fun() is now responsible for deleting
the vector too.
 
D

Daniel T.

zl2k said:
Class A {
public:
void GenerateBigData();
void getBigData();
private:
std::vector<int> bigData;
}

Basically, the bigData is generated within the class A. When I need it, I
just want to access the bigData by calling getBigData. I don't want a
duplicated copy of the bigData, a reference will be good. I don't know how
to implement it.

Assuming that your code *really* can't make a copy of bigData then:

(best solution) Move the code that needs bigData into class A.

(next best) Have class A provide a const iterator to the beginning and
end of bigData.

class A {
vector<int> bigData;
void generateBigData(); // called from A's c_tor
public:
typedef vector<int>::const_iterator const_iterator;

A(): bigData() { generateBigData(); }

const_iterator begin() const { return bigData.begin(); }
const_iterator end() const { return bigData.end(); }
};

(next best) return a const reference to bigData.

class A {
vector< int > bigData;
public:
typedef vector< int > BigDataType;

const BigDataType& getBigData() const { return bigData; }
};
 
L

loufoque

Roland Pibinger a écrit :
What would you do with the returned temporary vector? Assign it to
another vector?

#include <iostream>

class Foo
{
public:
Foo()
{
std::cout << "Constructor of " << this << std::endl;
}

Foo(const Foo &foo)
{
std::cout << "Copying " << &foo << " to " << this << std::endl;
}

~Foo()
{
std::cout << "Destructor of " << this << std::endl;
}
};

Foo bar()
{
Foo foo;
/* whatever */
return foo;
}

int main()
{
Foo foo = bar();
}

If you compile this with gcc in normal mode, you can see there is no
copying done. (you can disable those optimizations in gcc with
-fno-elide-constructors, and you will therefore see that it is copied twice)
Other modern compilers probably do so too.

I know old compilers like MSVC6 only partially optimize that, copying it
once.
 

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,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top