Forgive me if this has been asked before, I am sure it has but I couldn't find an answer I was happy with.
I am coming to cpp from a heavy Java background and would like to understand when to return a reference/pointer to an object rather than a copy.
for the following class definition:
class SpaceShip {
string name;
WeaponSystem weaponSystem; //represents some object, this is just an example, I dont have this type of object at all in my program
int hull;
string GetName() const {
return name;
}
WeaponSystem GetWeaponSystem() const {
return weaponSystem;
}
int GetHull() const {
return hull;
}
};
I know that returning a copy of things is expensive, I would think this means I want to avoid returning something like a string or weaponSystem by value, but an int by value is ok.
Is this right? I also know that I need to be aware of where things live in memory, does returning a reference to something in this class mean danger down the line if this object is destroyed and something still owns a reference to it's name?
On your last point, you definitely need to be a lot more careful about resource management in C++ than in Java. In particular, you need to decide when an object is no longer needed. Returning by reference has an effect of aliasing to the returned object. It is not noticeable when the object you are sharing is immutable, but unlike Java's Strings, C++ string are mutable. Therefore if you return name by value and then rename your SpaceShip, the caller would see the old name even after the renaming. If you return by reference, however, the caller will see a change as soon as ShaceShip is renamed.
When you deal with copying complex objects, you can decide how much is copied by providing a custom implementation of a copy constructor. If you decide to provide a copy constructor, don't forget the rule of three, and override the other two.
It "works" but you should have
const string& GetName() const {
It may also be beneficial to have the following also
const WeaponSystem& GetWeaponSystem() const {
Also, class is private by default, as such, your accessor functions are private.
the thing you have to know is every getter of your class must be prototype like that :
const <type> &className::getXXX() const
{
...
}
and every setter you make like that :
void className::setXXX(const <type> &)
{
...
}
Use reference when it's possible.
Sometimes, with complex object you can use pointer. That's depend on your code structure.
Related
I'm pretty noobish when it comes to c++, what is the better way of returning an object? I'm coming from the scripting world where Objects are always references, and am trying to achieve the same notion ... I'm basing this off of When to pass by reference and when to pass by pointer in C++?, where one user stated: "A good rule of thumb: "Use references when you can and pointers when you have to"."
// basic layer class
class Layer { private: Channel channel; // NEVER NULL };
// return object by pointer
Channel *Layer::getChannel() {
return &channel;
};
// return by reference
Channel& Layer::getChannel() {
return channel;
};
The problem with the second version is that the compiler will accept this line:
Channel channel = layer.getChannel(); // creates a copy BAD
when it should be:
Channel &channel = layer.getChannel(); // reference good
Is there any way to enforce a caller of the second option to force it to not create a new channel, or is the first option better anyways, even if it will never be NULL?
You need to adjust the Channel class itself so that it isn't copyable. If it is copyable, the user can copy it, and nothing you do can prevent it.
If copying is not a meaningful operation, then you can "disable" it. Simply define the copy constructor (Channel(const Channel&)) and the assignment operator (Channel& operator=(const Channel&)) to be private. Then any attempt at copying the class will result in a compile error.
On a side note, as others have mentioned, C++ is not the scripting languages you're familiar with. Everything is not a reference, and you're only setting yourself up for a world of pain by pretending otherwise. In C++, it is common to allocate objects on the stack, and pass objects by value, rather than passing references and pointers around.
Returning a reference (or const reference) is the normal way for a getter method to give the caller direct access to a member variable, so I'd recommend the second version of getChannel().
If you want to prevent callers from making inappropriate copies of Channel, you can accomplish that by making its copy constructor private. (If you want to prevent everything from making copies, even Channel itself, you can declare the constructor private and then not implement it.) But you should only do this if making a copy would actually be nonsensical, e.g. if the class represents some sort of underlying resource that can't be copied. Don't forbid copying just because you think the caller shouldn't need to; that's the caller's decision to make.
Return a copy of the object itself when copying isn't expensive for your purposes, and when you don't need to be able to change the original. This should be the default.
Channel Layer::getChannel() { return channel; };
Return by reference or pointer when copying is expensive or when you might want to change the value. Returning by reference allows you do to things like this:
layer.getChannel().clear();
And have it act on the channel that's in that layer.
Returning a pointer is similar to returning a reference except that it gives you a little more flexibility, in that the pointer can pointer to no object at all. I often a pointer when I want to be able to use store the "channel" in another class. I'd then do
class MyClass
{
// ...
void setChannel(Channel *pC) { m_pChannel = pC; }
private:
Channel * m_pChannel; // pointer to a channel that came from layer
}
Since you're returning a reference to the object, you are giving the users of the class direct access to the object, and if you're going to do that, why are you making the object private? Just make it public.
You can't stop a caller to create a new instance even when you use the pointer-return-version.
Channel* channel = new Channel(*layer.getChannel());
I know there is a way to achieve this goal. (For example, making Channle's ctor private so only it's static member function or its friend functions can create it.) However, I don't think this is the point of your question.
The point is that when you are making the member function returning either reference or pointer, you give a caller options he can choose whether he wants to copy it or reference it. Also, you can make your intention more clear by adding const to make it read-only.
For your case, I'd go for reference-return-version as the Channel cannot be null. If you do not want them to change the member variable, return const reference. Remember there is no single best way to decide return value type as it depends on what you want to say. Hope it helps! :)
Most important is maintaining readability with the code that's around you. "When in Rome, do as the Romans do." is important. You write it once, but everyone who has to maintain your code has to read it. If all of a sudden your code follows different guidelines than everyone around you, that means they need to first figure out your style, then figure out what you're doing...
One approach I've seen work very well is having pointers for things you change and const references for things you don't:
class Passenger {
...
};
class Car {
public:
int speed() const { return speed_; }
void set_speed(int speed) { speed_ = speed; }
const Passenger& passenger() const { return pass_;}
Passenger* mutable_passenger() { return &pass_; }
private:
int speed_;
Passenger pass_;
};
Clients of this class can do:
const Passenger& pass = car.passenger(); // no copy, but don't need to deal with NULL ptrs.
Other answers suggesting making copying a compile error are good ones.
Suppose I have a class Foo with a std::string member str. What should get_str return?
std::string Foo::get_str() const
{
return str;
}
or
const std::string& Foo::get_str() const
{
return str;
}
What is more idiomatic in C++?
The short answer is: it depends :-)
From the performance point of view returning a reference is (usually) better: you save the creation of a new std::string object. (In this case, the creation is costly enough and the size of the object is high enough to justify make this choice at least worth considering - but this is not always the case. With a smaller or built-in type the performance difference may be negligible, or returning by value may even be cheaper).
From the security point of view returning a copy of the original value may be better, as constness can be cast away by malicious clients. This is especially to be taken into consideration if the method is part of a public API, i.e. you(r team) have no full control over how the returned value is (mis)used.
One of the goals of having an accessor method is to try, at least to some extent, to abstract your class implementation from its interface.
Returning by value is better because there are no lifetime issues with the referenced object. Should you decide not to have a std::string member but, say, a std::stringstream or to create a std::string on the fly you don't have to change the interface.
Returning by const reference isn't the opposite of taking a parameter by const reference, taking a value by const reference doesn't tie your internal data representation to the external interface.
In general (unless there's a proven performance issue) I would return by value.
First of all there's a semantic difference, if your property changes do you want your clients to be updated of the change or get the value at the moment of calling the function?
There's the obvious correctness issue, if you return by reference the entity calling the function may hold on to the reference and may use it after your object was destructed (which is not so good).
Another problem is with multiple threaded code, if one thread reads from the const reference while you're updating the variable your in for lots of trouble.
In any case I think the most common use case is when the caller of the function stores the value in a variable.
string val = obj->get_str();
// use val now
If this is true (as opposed to cout << obj->get_str() where there is no variable) you always have to construct a new string for val even if you return by reference and since compilers can perform RVO the by-value version will not under-perform the by-const-ref variant.
In conclusion: if you know it's a performance issue and you are sure that the return value will not be stored for longer than your object will exist and you don't expect to be used from different threads, then it's OK to return by const reference.
Returning by value means you do not have to have an internal std::string stored somewhere in the class for which you return.
In a pure virtual method it is preferable not to assume that the std::string will be there and therefore to return a std::string by value.
In a concrete class where there is clearly a std::string member and you are just going to return a reference to it, you can, for efficiency, return it by const reference. Even if you have to change it later, you do not need to change functionality that uses the class.
In a multi-threaded model where the inner string might change between calls, of course, you probably need to return by value (assuming that users of the class will get a "snapshot" view of the string value at the time of the completion of the call).
Returning by reference is usually more efficient. I do however have a non-mutable reference-counted string class that you can return by value efficiently and I used to use that quite frequently.
By the way, some would recommend returning a std::string by const value. I do not think it is the best way to do it, as it prevents allowing the user to "swap" it into a local variable.
AFAIK, the rule is same as the one which is used while deciding whether to take a function parameter by value or const reference. If the sizeof the value being returned is small enough then I tend to use returning a copy else return a const reference.
Generally you should return PODs by value (e.g, int, short, char, long etc,) and a const reference for more complex types:
int getData() const;
short getMoreData() const;
const std::string& getName() const;
const ComplexObject& getComplexData() const;
I believe the second implementation (const reference) is correct as:
the returned object is immutable and therefore upholds the rules of encapsulation.
it's slightly more efficient as there is no copying of str.
However the first approach will work almost as well.
It depends on what you want to do with the return value.
This is better if you just want to make a query and not modify str.
const std::string& Foo::get_str() const
{
return str;
}
Otherwise, go for this:
std::string& Foo::get_str()
{
return str;
}
And if you want a copy/clone of str, then use this:
std::string Foo::get_str() const
{
return str;
}
I have a class which basically is a text manager. It can draw text and whatnot. I basically want the color and text std::string to only be a constant reference. Would it then be alright to do
class TextManager {
const std::string &text;
void draw(const std::string &text) const;
public:
TextManager(const std::string &text)
{
this->text = text;
}
void someMethod()
{
draw(text);
}
};
I want when the class that owns an instance of TextManager's text changes, the change is reflected in the TextManager.
would I be better off using a pointer?
thanks
If you never need to re-seat the reference (i.e. refer to a different object), then it's fine. But in my experience, you'll inevitably find out later down the line that you need to be more flexible, in which case a reference is a pain. It may be better to go with a pointer from the start.
But note that you can only initialise a member variable of reference type in the constructor initialiser list. (Also, you probably want to declare that constructor as explicit).
This code doesn't compile. this->text = text doesn't do what you think it does - it's not like Java where assigning a reference is like changing the pointer. reference = value will actually invoke the copy operator, so it will copy the value of the rhs to the lhs, either as member-by-member copy or using the operator= if it was overridden. Since your text is const, you can't do that.
So in this case, you have to use a pointer - references cannot be modified once initialized.
EDIT: Just to explain ways in which you could use a reference:
const std::string &text = yourString;
or:
TextManager(const std::string &textRef)
: text(textRef)
{
}
That way, you have a permanent reference to whatever string you have.
Once you have sorted out the initialisation (which other comments can help you with), using a reference will let you do what you want. That is, changes to the referenced std::string will affect your class because they are the same std::string.
You can get similar behaviour using std::string const* instead of std::string const&. As Oli brought out, using a pointer is more flexible. Since a pointer can be null and can be updated using a pointer will allow you to define a default constructor and a (probably compiler generated) assignment operator. Which may not be important in this class but likely will be in some other class you will write (eg if you want to put objects of this class into a std::vector). So you probably are better off using a pointer internally. Though you may wish to still pass a reference to the constructor and take the address of it to initialise the member.
In RAII, resources are not initialized until they are accessed. However, many access methods are declared constant. I need to call a mutable (non-const) function to initialize a data member.
Example: Loading from a data base
struct MyClass
{
int get_value(void) const;
private:
void load_from_database(void); // Loads the data member from database.
int m_value;
};
int
MyClass ::
get_value(void) const
{
static bool value_initialized(false);
if (!value_initialized)
{
// The compiler complains about this call because
// the method is non-const and called from a const
// method.
load_from_database();
}
return m_value;
}
My primitive solution is to declare the data member as mutable. I would rather not do this, because it suggests that other methods can change the member.
How would I cast the load_from_database() statement to get rid of the compiler errors?
This is not RAII. In RAII you would initialize it in the constructor, which would solve your problems.
So, what you are using here is Lazy. Be it lazy initialization or lazy computation.
If you don't use mutable, you are in for a world of hurt.
Of course you could use a const_cast, but what if someone does:
static const MyClass Examplar;
And the compiler decides it is a good candidate for Read-Only memory ? Well, in this case the effects of the const_cast are undefined. At best, nothing happens.
If you still wish to pursue the const_cast route, do it as R Samuel Klatchko do.
If you thought over and think there is likely a better alternative, you can decide to wrap your variable. If it was in class of its own, with only 3 methods: get, set and load_from_database, then you would not worry about it being mutable.
You are basically implementing a caching mechanism. Personally I think it's OK to mark cached data as mutable.
As Matthieu already pointed out, what you're trying to do here has little (if anything) to do with RAII. Likewise, I doubt that any combination of const and mutable is really going to help. const and mutable modify the type, and apply equally to all access to an object of that type.
What you seem to want is for a small amount of code to have write access, and anything else only read access to the value. Given the basic design of C++ (and most similar languages), the right way to do that is to move the variable into a class of its own, with the small amount of code that needs write access as part of (or possibly a friend of) that class. The rest of the world is given its read-only access via the class' interface (i.e., a member function that retrieves the value).
The (presumably stripped down) MyClass you've posted is pretty close to right -- you just need to use that by itself, instead of as part of a larger class with lots of other members. The main things to change would be 1) the name from MyClass to something like lazy_int, and 2) (at least by my preference) get_value() should probably be renamed to operator int(). Yes, m_value will probably need to be mutable, but this doesn't allow other code to write the value, simply because other code doesn't have access to the value itself at all.
Then you embed an object of that type into your larger class. The code in that outer class can treat it as an int (on a read-only basis) thanks to its operator int(), but can't write it, simply because the class doesn't give any way to do so.
[ LOOK MA! NO CASTS! :)) ]
struct DBValue
{
int get_value();
private:
void load_from_database();
int value;
};
struct MyClass
{
MyClass(): db_value(new DBValue()) {}
~MyClass() { delete db_value; }
int get_value() const;
private:
DBValue * const db_value;
};
int MyClass::get_value() const
{
return db_value->get_value(); // calls void load_from_database() if needed
}
The idea is to have a politically correct MyClass with const methods not mutating anything but calling both const and non-const methods of aggregated objects via const pointers.
Don't use const_cast here, or you're asking for trouble. Using mutable in this case shouldn't be a problem, but if the profiler didn't suggest otherwise then I think users would be less surprised to see an object that is expensive to construct than an accessor method that is expensive to call the first time.
If your method changes the state of the object (e.g. by changing the state of the underlying database), then the method should not be const. In that case you should have a separate, non-const load-method, that has to be called before the const getter can be called.
This method would require neither const_cast not mutable, and would make the potentially expensive operation explicit.
What's better as default, to return a copy (1) or a reference (2) from a getter function?
class foo {
public:
std::string str () { // (1)
return str_;
}
const std::string& str () { // (2)
return str_;
}
private:
std::string str_;
};
I know 2) could be faster but don't have to due to (N)RVO. 1) is safer concerning dangling references but the object will probably outlife or the reference is never stored.
What's your default when you write a class and don't know (yet) whether performance and lifetime issues matter?
Additional question: Does the game change when the member is not a plain string but rather a vector?
Well it really depends on what you expect the behaviour to be, by default.
Do you expect the caller to see changes made to str_ unbeknownst(what a word!) to them? Then you need to pass back a reference. Might be good if you can have a refcounted data member and return that.
If you expect the caller to get a copy, do 1).
My rule of thumb is to return a copy for simple basic datatypes such as int, string etc. For a bit more complicated structures where copying may be costlier (like vector you mentioned) I prefer to return a const-reference.
The compiler will not be able to perform (N)RVO in this case. The (named) return value optimization is an optimization where the compiler creates the function auto variables in the place of the return value to avoid having to copy:
std::string f()
{
std::string result;
//...
return result;
}
When the compiler sees the code above (and assuming that if any other return is present it will also return the result variable) it knows that the variable result has as only possible fate being copied over the returned temporary and then destroyed. The compiler can then remove the result variable altogether and use the return temporary as the only variable. I insist: the compiler does not remove the return temporary, it removes the local function variable. The return temporary is required to fulfill the compilers call convention.
When you are returning a member of your class, the member must exist, and the call convention requires the returned object to be in a particular location (stack address usually). The compiler cannot create the method attribute over the returned object location, nor can it elide making the copy.
I'm returning a reference, because a string seems not "cheap to copy" to me. It's a complex data type with dynamic memory management and all that.
The "if you want the caller to get a copy, you should return by value" argument is moot, because it doesn't preclude copies at all. The caller can still do the following and get a copy anyway
string s = obj.str();
You need to explicitly create a reference on the caller side to be able to refer to the data member directly afterwards - but why would you do that? There definitely are enough user defined types that are cheap to copy
Smart Pointers
Iterators
All of the non-class types.
Returning a reference to an object's internals as part of its public interface can be a code smell if not outright bad design.
Before returning a reference to an internal object in a public interface, the designer should pause. Doing so couples users of your class to part of your design. Often it is outright unnecessary, sometimes it indicates further design work is needed. At times it is necessary, as commenters have noted.
If there is no special reason to use a value type as return value, I always return a const reference. If I need (or expect to need) a (writable) copy, I add a copy ctor and an assignment operator to the returned class if not already available. For the usage think of:
const MyClass & ref = container.GetAt( 1234 ); // need only reference
MyClass copy = container.GetAt( 1234 ); // get writable copy
Actually this is quite straight forward, isn't it?
if its a small basic type - primatives like int and long and their wrappers and other basic things like 'Point' - return a copy
if its a string, or any other complex type - return a reference.
The only problem I have with returning a const-reference, which is something I would typically do for non basic types, is that there is nothing to stop the caller removing the "const"ness and then modifying the value.
Personally, I'd suggest that such code is a bug. If they know you're returning a reference and continue to cast away the const then it's on their head.