Say, I develop a complex application: Within object member functions, should I modify only those objects, that are passed to the member functions as parameters, or can I access and modify any other objects I have access to(say public or static objects)?
Technically, I know that it is possible to modify anything I have access to. I am asking about good practices.
Sometimes, it is bothering to pass as an argument everythying i will access and modify, especially if I know that the object member function will not be used by anybody else, but me. Thanks.
Global state is never a good idea (though it is sometimes simpler, for example logging), because it introduces dependencies that are not documented in the interface and increase coupling between components. Therefore, modifying a global state (static variables for example) should be avoided at all costs. Note: global constants are perfectly okay
In C++, you have the const keyword, to document (and have the compiler enforce) what can be modified and what cannot.
A const method is a guarantee that the visible state of an object will be untouched, an argument passed by const reference, or value, will not be touched either.
As long as it is documented, it is fine... and you should strive for having as few non-const methods in your class interface and as few non-const parameters in your methods.
If you have a class with member variables, then it is entirely acceptable to modify those member variables in a member method regardless of whether those member variables are private, protected, or public. This is want is meant by encapsulation.
In fact, modifying the variables passed into the member method is probably a bad idea; returning a new value is what you'd want, or getting a new value back from a separate member method.
Related
Coming from Java, C++ is breaking my brain.
I need a class to hold a reference to a variable that's defined in the main scope because I need to modify that variable, but I won't be able to instantiate that class until some inner loop, and I also won't have the reference until then. This causes no end of challenges to my Java brain:
I'm used to declaring a variable to establish its scope, well in advance of knowing the actual value that will go in that variable. For example, creating a variable that will hold an object in my main scope like MyClass test; but C++ can't abide a vacuum and will use the default constructor to actually instantiate it right then and there.
Further, given that I want to pass a reference later on to that object (class), if I want the reference to be held as a member variable, it seems that the member variable must be initialized when it's declared. I can't just declare the member variable in my class definition and then use some MyClass::init(int &myreference){} later on to assign the reference when I'll have it in my program flow.
So this makes what I want to do seemingly impossible - pass a reference to a variable to be held as a member variable in the class at any other time than instantiation of that class. [UPDATE, in stack-overflow-rubber-ducking I realized that in this case I CAN actually know those variables ahead of time so can side-step all this mess. But the question I think is still pertinent as I'm sure I'll run into this pattern often]
Do I have no choice but to use pointers for this? Is there some obvious technique that my hours of Google-fu have been unable to unearth?
TLDR; - how to properly use references in class member variables when you can't define them at instantiation / constructor (ie: list initialization)?
Declare reference member variable that you won't have at instantiation
All references must be initialised. If you don't have anything to initialise it to, then you cannot have a reference.
The type that you seem to be looking for is a pointer. Like references, pointers are a form of indirection but unlike references, pointers can be default initialised, and they have a null state, and can made to point to an object after their initialisation.
Important note: Unlike Java references, C++ references and pointers do not generally extend the lifetime of the object that they refer to. It's very easy to unknowingly keep referring to an object outside of its lifetime, and attempting to access through such invalid reference will result in undefined behaviour. As such, if you do store a reference or a pointer to an object (that was provided as an argument) in a member, then you should make that absolutely clear to the caller who provides the object, so that they can ensure the correct lifetime. For example, you could name the class as something like reference_wrapper (which incidentally is a class that exists in the standard library).
In order to have semantics similar to Java references, you need to have shared ownership such that each owner extends the lifetime of the referred object. In C++, that can be achieved with a shared pointer (std::shared_ptr).
Note however, that it's generally best to not think in Java, and translate your Java thoughts into C++, but it's better to rather learn to think in C++. Shared ownership is convenient, but it has a cost and you have to consider whether you can afford it. A Java programmer must "unlearn" Java before they can write good C++. You can also subsitatute C++ and Java with most other programming languages and same will apply.
it seems that the member variable must be initialized when it's declared.
Member variables aren't directly initialised when they are declared. If you provide an initialiser in a member declaration, that is a default member initialiser which will be used if you don't provide an initialiser for that member in the member initialiser list of a constructor.
You can initialise a member reference to refer to an object provided as an argument in a (member initialiser list of a) constructor, but indeed not after the class instance has been initialised.
Reference member variables are even more problematic beyond the lifetime challenges that both references and pointers have. Since references cannot be made to point to other objects nor default initialised, such member necessarily makes the class non-"regular" i.e. the class won't behave similar ways as fundamental types do. This makes such classes less intuitive to use.
TL;DR:
Java idioms don't work in C++.
Java references are very different from C++ references.
If you think that you need a reference member, then take a step back and consider another idea. First thing to consider: Instead of referring to an object stored elsewhere, could the object be stored inside the class? Is the class needed in the first place?
I got a question regarding to these two possibilities of setting a value:
Let's say I got a string of a class which I want to change. I am using this:
void setfunc(std::string& st) { this->str = st; }
And another function which is able to do the exact same, but with a string reference instead of a void for setting a value:
std::string& reffunc() { return this->str; }
now if I am going to set a value I can use:
std::string text("mytext");
setfunc(text);
//or
reffunc() = text;
Now my question is if it is considered bad at using the second form of setting the value.
There is no performance difference.
The reason to have getters and setters in the first place is that the class can protect its invariants and is easier to modify.
If you have only setters and getters that return by value, your class has the following freedoms, without breaking API:
Change the internal representation. Maybe the string is stored in a different format that is more appropriate for internal operations. Maybe it isn't stored in the class itself.
Validate the incoming value. Does the string have a maximum or minimum length? A setter can enforce this.
Preserve invariants. Is there a second member of the class that needs to change if the string changes? The setter can perform the change. Maybe the string is a URL and the class caches some kind of information about it. The setter can clear the cache.
If you change the getter to return a const reference, as is sometimes done to save a copy, you lose some freedom of representation. You now need an actual object of the return type that you can reference which lives long enough. You need to add lifetime guarantees to the return value, e.g. promising that the reference is not invalidated until a non-const member is used. You can still return a reference to an object that is not a direct member of the class, but maybe a member of a member (for example, returning a reference to the first name part of an internal name struct), or a dereferenced pointer.
But if you return by non-const reference, almost all bets are off. Since the client can change the value referenced, you can no longer rely on a setter being called and code controlled by the class being executed when the value changes. You cannot constrain the value, and you cannot preserve invariants. Returning by non-const reference makes the class little different from a simple struct with public members.
Which leads us to that last option, simply making the data member public. Compared to a getter returning a non-const reference, the only thing you lose is that the object returned can no longer be an indirect member; it has to be a direct, real member.
On the other side of that equation is performance and code overhead. Every getter and setter is additional code to write, with additional opportunities for errors (ever copy-pasted a getter/setter pair for one member to create the same for another and then forgot to change one of the variables in there?). The compiler will probably inline the accessors, but if it doesn't, there's call overhead. If you return something like a string by value, it has to be copied, which is expensive.
It's a trade-off, but most of the time, it's better to write the accessors because it gives you better encapsulation and flexibility.
We cannot see the definition of the member str.
If it's private, your reffunc() exposes a reference to a private member; you're writing a function to violate your design, so you should reconsider what you're doing.
Moreover, it's a reference, so you have to be sure that the object containing str still exists when you use that reference.
Moreover, you are showing outside implementation details, that could change in the future, changing the interface itself (if str becomes something different, setfunc()'s implementation could be adapted, reffunc()'s signature has to change).
It's not wrong what you wrote, but it could be used in the wrong way. You're reducing the encapsulation. It's a design choice.
It's fine. However, you have to watch out for these pitfalls:
the referenced object is modifiable. When you return a non-const reference, you expose data without protection against modifications. Obvious, but be aware of this anyway!
referenced objects can go out of sope. If the referenced object's lifetime ends, accessing the reference will be undefined behavior. However, they can be used to extend the lifetime of temporaries.
The way you used the reffunc() function is considered bad coding. But (as mentioned in the comments), generally speaking, returning references is not bad coding.
Here's why reffunc() = text; is considered bad coding:
People usually do not expect function calls on the left hand of an assignment, but on the right side. The natural expectation when seeing a function call is that it computes and returns a value (or rvalue, which is expected to be on the right hand side of assignment) and not a reference (or lvalue, which is expected to be on the left hand side of assignment).
So by putting a function call on the left hand side of the assignment, you are making your code more complicated, and therefore, less readable. Keeping in mind that you do not have any other motivations for it (as you say, performance is the same, and it usually is in these situations), good coding recommends that you use a "set" function.
Read the great book "Clean Code" for more issues on clean coding.
As for returning references in functions, which is the title of your question, it is not always bad coding and is sometimes required for having cleaner and briefer code. Specifically many operator overloading features in c++ work properly if you return a reference (see operator[] in std::vector and the assignment operator which usually help the code become more readable and less complex. See the comments).
I went through the already existing thread on this topic and wasn't convinced with the explanation.
What I could pick up from there was:
When a non-static member function is declared const, the restriction is imposed on this this pointer. As static member functions donot involve the this pointer, they cannot be declared const.
Is that it? Doesn't sound too convincing to me. I mean, I'm not questioning why it's so. I just want to to the reason why.
A const non-static member function is allowed to modify local, static, and global variables; it just isn't allowed to modify members of its class through the this pointer (implicitly or explicitly). A const static member function, therefore, would be allowed to modify local, static, and global variables, just like a non-member function. This would make the const meaningless.
If you want to write a function that isn't allowed to modify any non-local variables at all, you can declare it constexpr, although that also imposes additional restrictions.
The reason the const/non-const distinction for functions is important is that there are contexts in which it is not legal to call a non-const function. So the distinction can be used to enforce invariants.
For example, if you pass a non-const reference to a function, if your class is properly designed, you are guaranteed that the function can't change the value of the thing the reference refers to. This allows you to avoid copies.
Also, a non-const reference can't bind to a temporary. This permits functions to signal whether they return values through references or just take a value. You will get an error at compile time if you inadvertently ignore a returned value because a temporary was created unexpectedly.
None of this would apply to static functions because there is no context in which you would be prohibited from calling them. So the entire rationale for the distinction does not exist with static functions.
What is the Design and Performance impact for making all functions static which do not touch the member variable of the class?
You should actually consider making them non-static free functions, as explained in detail in this question. This question is also very interesting.
In a nutshell, these question explain that you should prefer non-friend non-member functions whenever possible (meaning when they do not access non-public members).
What are Design and Performance impact for making all function static which do not touch member variable of class?
performance: static member functions may be slightly faster than non-static member functions because they don't need to pass a this pointer, but you're unlikely to notice the difference; where inlining is used there may not be one. Further, pointers to a static function may be used directly, whereas "pointers" to non-static member functions are typically offsets/indices and require a this pointer for use; the run-time CPU operations involved can be expected to be slightly more complicated.
design: the choice between static and non-static member function can safely be made on the basis of the need to access an object's non-static member data in order to fully perform the expected operation. If you're generally comfortable with OOP and it doesn't seem intuitive and sensible to call the function using the notation object.fn(x, y, z) - that the function lends itself to being perceived as an operation on the current state of that specific object - then it probably shouldn't be a non-static member.
Ignoring the question as I understand it and looking at the wider terrain, free functions do have their own advantages as discussed in other replies; countering that the tighter association of static members can help programmers find potentially useful routines - all depending on the tools and habits they have.
Performance-wise, static member functions are faster and use less stack space because they do not need to pass a this pointer. But this isn't a significant cost.
Regarding design, you should ask yourself why the functions are members of the class if they do not access its data members? There certainly are design patterns that include static functions. However, a widely favored approach to class design is to choose the minimum number of functions necessary to expose the functionality of the class while keeping its data hidden. This makes it easier to change the internals of the class without knock-on changes to the code which uses the class. Such an approach has little use for static functions as they cannot provide access to the data.
Absolutely yes. The non-static member functions are meant to cater the non-static member variables. If variables are not used then the function should be made static which makes your design cleaner and you can avoid passing this as the 1st hidden argument (which betters the performance a little).
[Note: On funny side there is one notable exception:
struct A {
virtual void foo (int) = 0;
};
Even though you don't have member used inside foo() you can't make it static ! :)]
Sometimes it makes sense to make a function virtual even if it does not access any instance members - for example to return some class-related properties (something like virtual bool eatsPlants() in the animal class hierarchy). Then it cannot be static because there are no virtual static members in C++.
Performance of static member functions vs free functions?
There is absolutely no performance difference between static member functions and free functions.
Performance of static member functions vs non static member functions?
Typically static member function are used to eliminate the need for an object and eliminate the extraneous this argument and that is the only performance advantage over non static member functions but it is hardly noticeable.
It depends. First, of course, if the function is to be virtual, then it
can't be static. (Most of the member functions I have which don't touch
a member variable are virtual. Otherwise, why make it a member at all?)
Otherwise, it depends on the role of the function in the class. If it
is fundamentally independent of any instance of the class (e.g. it sets
some global parameter of the class, which affects all instances), then
it should be static; such functions should be fairly rare, however. If
on the other hand, it only incidental that it doesn't touch a member
variable;, if conceptually, it does involve the specific instance, then
make it a member. (This is frequent in the case of virtual functions,
but probably very rare otherwise.)
After reading this, it is my understanding that declaring a method as const prevents it from accidentally modifying the class's member variables.
Are const methods commonly used?
Should they be used for everything that shouldn't modify member variables?
Yes, const should always be used, when appropriate.
It lets your compiler check your application logic, statically asserting const-correctness for free!
Some people even say that const should be the default, and you should be forced to use mutable for what is non-constant.
I use const extensively to communicate design intent. If I intended that a method was a pure query, and not a modification function, I would both enforce that and communicate it with a 'const' in the signature.
I encourage you to look at Meyer's thoughts on the matter of side-effect-free functions, and the implications that has on enabling testing.
Just my testimony.
Some years ago, I was still against the use of const, just because of the constraints in design and writing longer function signatures... and so on...
But one of my project leaders always insisted, all the time, reminding me: "You should use const function, it avoids accidents and doing non-sense".
And one day I faced an impossible bug to find. Days after days after days... A nightmare. The design was too big for me too see so as I could grasp it in its whole. I searched in vain until I decided I was lost.
Then I spent two days redefining ALL the functions that should be const. I mean it, two days. (Recompilations were long as it was a 5 millions lines of code project).
And then: simply I found the bug... rather the Compiler found the bug for me: In a getter-like method, which should have given me the prefered size of a gui control, the code was actually computing the size, but it was also caching its size and updating its size... Thus modifying the object.
Now, sometimes I forget to put const. But if I notice it, I correct it.
Adding const to a member function allows it to be called on const references to an object, because it guarantees that instance variables won't be changed. Const references occur in various places throughout the STL, so it makes sense to mark member functions as const where the function doesn't intend to modify the state of an object.
Note: it is possible to mark certain instance variables as mutable so they can be changed even by const functions. This is useful to implement look-up caches, for example.
Declaring a method that shouldn't modify member variables:
Assures that what you think is what is happening, i.e. that you're not accidentally modifying a variable somewhere.
Declares to callers of the function that this method doesn't modify member variables, removing the need to read over the code or rely on documentation that says so.
So yes, use const wherever it makes sense. They're not as widely used as I'd like to see though, most likely because the majority of developers don't see the huge benefit.
If you forget to mark an accessor as const, the compiler will not allow the method to be called on const objects or references to const objects. So yes, marking accessors as const is important.
If you have a const reference or pointer (i.e. pointer to const) of a class object then you can ONLY call const member methods of the class.
So if someone "forgot" to make a "get" method const, you would not be able to call it with a const reference (There is a workaround with const_cast but we don't want to use that!).
So yes, if the class is not going to be modified by the method then it should be const.
Note: there are some occasions that you do want to modify a variable as an "implementation detail", eg lazy-loading or to lock a mutex. In such a case you can still make the method const but make that member variable "mutable".
If you are writing a virtual method, it should be const if no derived class will need it to be mutable.
You should use the const keyword whenever possible.
It prevent you from the mistakes in the code.
It increase the readability of the code very much.
Everyone who is reading the header and seeing const keywords can immediately understand that a const method does not change the state of an object and can be used with no being afraid he will change the object for example