Luan Nico
Luan Nico

Reputation: 5917

Returning an object or a pointer in C++

In C++, should my method return an object or a pointer to an object? How to decide? What if it's an operator? How can I define?

And one more thing - if the pointer turns to be a vector, how can I find out its size after returned? And if it's impossible, as I think it is, how should I proceed to correctly return an array without this limitation?

Upvotes: 16

Views: 15390

Answers (3)

Johan Lundberg
Johan Lundberg

Reputation: 27028

In C++, should my method return an object or a pointer to an object? How to decide?

Since C++11 we have move semantics in C++ which means that it as easy as before and now also fast to return by value. That should be the default.

What if it's an operator? How can I define?

Many operators such as operator= normally return a reference to *this

X& X::operator=(X rhs); 

You need to look that up for each operator if you would like to comply with the usual patterns (and you should). Start here: Operator overloading

As pointed out by Ed S. return value optimization also applies (even before C++11) meaning that often object you return need neither be copied or moved.

So, this is now the way to return stuff:

std::string getstring(){ 
   std::string foo("hello");
   foo+=" world";
   return foo;
}

The fact that I made a foo object here is not my point, even if you did just do return "hello world"; this is the way to go.

And one more thing - if the pointer turns to be a vector, how can I find out its size after returned? And if it's impossible, as I think it is, how should I proceed to correctly return an array without this limitation?

The same goes for all copyable or movable types in the standard (these are almost all types, for example vectors, sets, and what not), except a few exceptions. For example std::arrays do not gain from moving. They take time proportional to the amount of elements. There you could return it in a unique_ptr to avoid the copy.

typedef std::array<int,15> MyArray;
std::unique_ptr<MyArray> getArray(){ 
  std::unique_ptr<MyArray> someArrayObj(new MyArray());
  someArrayObj->at(3)=5;
  return someArrayObj;
}

int main(){
  auto x=getArray();
  std::cout << x->at(3) <<std::endl; // or since we know the index is right: (*x)[3]
}

Now, to avoid ever writing new anymore (except for experts in rare cases) you should use a helper function called make_unique. That will vastly help exception safety, and is as convenient:

std::unique_ptr<MyArray> getArray(){ 
  auto someArrayObj=make_unique<MyArray>();
  someArrayObj->at(3)=5;
  return someArrayObj;
}

For more motivation and the (really short) implementation of make_unique, have a look here: make_unique and perfect forwarding

Update

Now make_unique is part of the C++14 standard. If you don't have it, you can find and use the whole implementation from the proposal by S.T.L.:

Ideone example on how to do that

Upvotes: 10

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726639

In C++, should my method return an object or a pointer to an object?

You should return an object by default. Usual exceptions are functions that return a subclass of a given class, and when returning nothing is a legal option for a function1.

What if it's an operator?

Operators return references or objects; although it is technically possible to return pointers from overloaded operators, it is not usually done.

And one more thing - if the pointer turns to be a vector, how can I find out it's size after returned?

I think you meant an array rather than a vector, because std::vector has a size() member function returning the size of the vector. Finding the size of a variable-length array is indeed not possible.

And if it's impossible, as I think it is, how should I proceed to correctly return an array without this limitation?

You should use std::vector, it does not limit you on the size or the type of elements that go into it.


1 In which case you return NULL or nullptr in C++11.

Upvotes: 4

leftaroundabout
leftaroundabout

Reputation: 120711

Unless there is some specific reason to use plain pointers, always return something memory-safe. In an estimated 95% of all cases, simply returning objects is fine, and then return-by-value is definitely the canonical thing to do (simple, efficient, good!).

The remaining 5% are mostly when the returned object is runtime-polymorphic; such an object can't be returned by value in C++ since that would happen on the stack. In such a case, you should return a smart pointer to the new object, in C++11 the standard choice is std::unique_ptr. There is also the case when you want to optionally return something, but that's IMO a case for a specific container, not for pointers, boost::optional or something like that.

Upvotes: 2

Related Questions