Can const functions call non-const functions on local objects? - c++

I have a question regarding const functions: can a const function call non-const functions on local objects in the function? Here's an example of what I'm talking about:
template <class T>
Set<T> Set<T>::setUnion (const Set<T> & other) const
{
Set<T> unionSet; //create union set
unionSet.merge(internalStorage); //merge it with our current set
unionSet.merge(other.internalStorage); //merge it with other set, duplicates will not be added
return unionSet;
}
This function takes two sets and returns the union of the sets. The problem though is that the merge function is not const and the merge function also calls the add function which is also not const, so I cannot see any other way to create a union set with solely these two functions given that the setUnion function has to be const.
PS: I know the solution without doing a const function, the reason I'm doing it this way is because my professor defined it as such. Thanks.

Yes. The only restriction on a const member function is that it can't modify the object its called on; it can modify any other (non-const) object.

A const member function means that the this it receives has type roughly equivalent to T const *const this1.
That means you can't invoke any non-const functions via this, but it does not affect anything you do that doesn't go through this (explicitly or implicitly).
1. Technically, you can't really write out the type of this truly correctly, but the type I've given here is close enough for the current discussion.

Related

Defining hash and equality functions for nonstandard objects

I'm having some trouble defining hash and equality functions for objects. I'm using the objects as keys for std::unordered_map's. I have two keys aKey and unaccessibleKey. I can add an equailty operator overload to aKey, but I can't to unaccessibleKey because it's "unaccessible". I have tried doing the following, but I'm not sure if I'm using the right syntax for everything, and I don't know how to define an equality function for unaccessibleKey. Here's what I've tried:
struct aKeyHash
{
std::size_t operator()(const aKey& k) const
{
return k.getnonconstmem()->nonconstfunc();
};
}
struct unaccessibleKeyHash
{
std::size_t operator()(const unaccessibleKey& k) const
{
return k.noncostmem;
};
}
bool UnaccessibleEqualityFunction(const unaccessibleKey& p1, const unaccessibleKey& p2)
{???} //i dont know how to define this
std::unordered_map<aKey, std::unordered_map<unaccessibleKey, aValue, unaccessibleKeyHash, unaccessibleEqualityFunctions>, aKeyHash>
Am I doing this right (aside from the function that I don't know how to define)? As a side note, when I tried calling k.getnonconstmem()->nonconstfunction() I get an error.
It would be possible to use unaccessibleKey::nonconstmem as the key itself because it's actually a hashed int, but that may lead to complications later down the line that I don't want to deal with.
So my questions the are: 1. do I have the right syntax for the hashes, 2. how do I define the equality function, 3. why would I get the error with the const/nonconst mixing?
do I have the right syntax for the hashes
The hash structures themselves have correct syntax. Whether the definitions of the hash functions are correct, depends on the definition of the target types. In particular, if getnonconstmem() is a non-const function, then calling it on a const reference is ill-formed. You may only call const functions on const objects.
how do I define the equality function
Return true when the objects have equal logical state, and false otherwise. An example, which assumes that the state consists of a single member:
return p1.member == p2.member;
why would I get the error with the const/nonconst mixing?
The shown code is not sufficient to explain why there would be errors. You will get errors if you try to modify, or call non-const functions on const objects, or any object through pointer or reference to const.

C++ How to use std::sort with comparator based on your class' function

Im trying to sort my vector depending on value returned by function calculateDistance() which returns double value. I guess the problem is caused by permutationCopmarator method. .cpp file looks like this:
bool TSPgenetic::permutationComparator(int* i, int* j){
return calculateDistance(i) < calculateDistance(j);
}
void TSPgenetic::chooseNewPopulation(){
sort(population->begin(), population->end(), permutationComparator);
sort(children->begin(), children->end(), permutationComparator);
`....`
}
Header file fragment:
bool permutationComparator(int*, int*);
Passing permutationComparator as the third parameter of std::sort is not valid. Only static class members is valid and functor objects. To resolve the issue, here's four choices:
Create a closure object using lambda expression and do your comparison there.
std::sort(population->begin(), population->end(), [](const int *i1, const int *i2){return calculateDistance(i1) < calculateDistance(i2);});
You can use std::bind, if your comparsion function needs not to be static.
auto comp_func = std::bind(&TSPgenetic::permutationComparator, this, std::placeholders::_1, std::placeholders::_2);
std::sort(population->begin(), population->end(), comp_func);
Make your comparison function static, if it's possible.
Overload bool operator () ( const int *i1, const int *i2 ) in your class in order that your class to be a functor object.
Note that logically a comparison function should not to be a member function. It is a function that takes two objects and determines their orders. So, almost in all cases, only the third option applies.

comparator for sorting a vector contatining pointers to objects of custom class

By this question I am also trying to understand fundamentals of C++, as I am very new to C++. There are many good answers to problem of sorting a vector/list of custom classes, like this. In all of the examples the signature of comparator functions passed to sort are like this:
(const ClassType& obj1, const ClassType& obj2)
Is this signature mandatory for comparator functions? Or we can give some thing like this also:
(ClassType obj1, ClassType obj2)
Assuming I will modify the body of comparator accordingly.
If the first signature is mandatory, then why?
I want to understand reasons behind using const and reference'&'.
What I can think is const is because you don't want the comparator function to be able to modify the element. And reference is so that no multiple copies are created.
How should my signature be if I want to sort a vector which contains pointers to objects of custom class? Like (1) or (2) (see below) or both will work?
vertor to be sorted is of type vector
(1)
(const ClassType*& ptr1, const ClassType*& ptr2)
(2)
(ClassType* ptr1, ClassType* ptr2)
I recommend looking through This Documentation.
It explains that the signature of the compare function must be equivalent to:
bool cmp(const Type1& a, const Type2& b);
Being more precise it then goes on to explain that each parameter needs to be a type that is implicitly convertable from an object that is obtained by dereferencing an iterator to the sort function.
So if your iterator is std::vector<ClassType*>::iterator then your arguments need to be implicitly convertable to ClassType*.
If you are using something relatively small like an int or a pointer then I would accept them by value:
bool cmp(const ClassType* ptr1, const ClassType* ptr2) // this is more efficient
NOTE: I made them pointers to const because a sort function should not modify the values it is sorting.
(ClassType obj1, ClassType obj2)
In most situations this signature will also work, for comparators. The reason it is not used is because you have to realize that this is passing the objects by value, which requires the objects to be copied.
This will be a complete waste. The comparator function does not need to have its own copies of its parameters. All it needs are references to two objects it needs to compare, that's it. Additionally, a comparator function does not need to modify the objects it is comparing. It should not do that. Hence, explicitly using a const reference forces the compiler to issue a compilation error, if the comparator function is coded, in error, to modify the object.
And one situation where this will definitely not work is for classes that have deleted copy constructors. Instances of those classes cannot be copied, at all. You can still emplace them into the containers, but they cannot be copied. But they still can be compared.
const is so you know not to change the values while you're comparing them. Reference is because you don't want to make a copy of the value while you're trying to compare them -- they may not even be copyable.
It should look like your first example -- it's always a reference to the const type of the elements of the vector.
If you have vector, it's always:
T const & left, T const & right
So, if T is a pointer, then the signature for the comparison includes the comparison.
There's nothing really special about the STL. I use it for two main reasons, as a slightly more convenient array (std::vector) and because a balanced binary search tree is a hassle to implement. STL has a standard signature for comparators, so all the algorithms are written to operate on the '<' operation (so they test for equality with if(!( a < b || b < a)) ). They could just as easily have chosen the '>' operation or the C qsort() convention, and you can write your own templated sort routines to do that if you want. However it's easier to use C++ if everything uses the same conventions.
The comparators take const references because a comparator shouldn't modify what it is comparing, and because references are more efficient for objects than passing by value. If you just want to sort integers (rarely you need to sort just raw integers in a real program, though it's often done as an exercise) you can quite possibly write your own sort that passes by value and is a tiny bit faster than the STL sort as a consequence.
You can define the comparator with the following signature:
bool com(ClassType* const & lhs, ClassType* const & rhs);
Note the difference from your first option. (What is needed is a const reference to a ClassType* instead of a reference to a const ClassType*)
The second option should also be good.

const input vs non-const output

I have a function which traverses a tree of objects and does not modify any of the objects in the tree.
The function looks something like this:
static Node* findMatchingNode(const Node& root, const SomeFilterData& d);
struct Node {
Node* left;
Node* right;
};
The function can return the root or any object in the tree or nothing. It's obvious than with given declaration I have to perform const_cast somewhere, which is forbidden in most cases.
Is it acceptable for a function to guarantee constness and at the same time allow anyone to modify its output?
EDIT. I haven't stated this clearly, my function really does not modify any of the nodes in the tree, doesn't create new Node, it's pure function. I'd like to always have const qualifier there to tell everyone clearly that the function doesn't modify anything
EDIT. The unspoken problem behind is that there is no legal way to express constness of the input during the function execution (and only inside the function) without enforcing the output constness.
As always, you cannot modify const data because it is constant. In particular:
Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior.
(from here)
So if a pointer to the const input argument root is a sensible outcome, the return type should be const as well. You should be really careful with returning pointers anyway: As of now, your function can return a pointer to a temporary!
So better return a boost::optional<Node> or an std::optional<Node> (if the latter makes it into C++17 and you use that standard).
If your function only makes sense for a modifiable input root (e.g. if the outcome must be modifiable and the outcome can be the address of root), drop the const in your declaration. That would also prevent the input root from being a temporary.
Most likely the cleanest fix for your potential XY-problem:
If it fits your use-case (I find it highly unlikely that it does not), the most likely even better option would be defining your algorithm on a iteratable data structure like a tree or a list (whatever your Node is a node of) and then return an iterator to the matching node, or a past-the-end iterator (with respect to the high-level structure) if no such node exists.
As for the const-vs.-non-const discussion: With the iterator option you can differentiate between the constness of the high level structure and the reference node you compare stuff with by taking non-const iterators over the high level structure and a const & argument for the reference input node (where a temporary now would not be a problem).
From what I can see from your question, your function might even be replaceable with std::find_if. Then you would not have this problem in the first place.
Your code is not const-correct, it drops a const. This is why you have the problem of a "required" const cast. Don't do that:
static const Node* findMatchingNode(const Node& root, const SomeFilterData& d);
You may point out that you may want to call this function from another function that does modify the nodes, and thus wants a non-const result. As such, that should be a new function with a totally different signature:
static Node* findMatchingNode(Node& root, const SomeFilterData& d);
You may point out that these have identical bodies, and there's the DRY principle (DRY = Don't Repeat Yourself = Don't have copy-pasted code). Yes, so just take a shortcut here: const_cast. I think it's ok in this case, because it's only purpose is shared code, and it's clear that it's not violating any const-correctness principles.
//This function does not modify anything
static Node* findMatchingNode(Node& root, const SomeFilterData& d) {
return const_cast<Node*>(findMatchingNode(const_cast<const Node&>(root),d));
}
Loki Asari suggests adding a third private function findMatchingNodeCommon() that both versions of findMatchingNode() call. Then you can get away with one less const_cast. If you want to go extreme then you can make findMatchingNodeCommon() templated and then all const_casts go away. I think it's not worth the bother, but they're very valid opinions, so worth a mention.
According to the Standard C++ Foundation:
What is the relationship between a return-by-reference and a const member function?
If you want to return a member of your this object by reference from an inspector method, you should return it using reference-to-const (const X& inspect() const) or by value (X inspect() const).
So yeah, you should be returning either by value or a const reference/pointer. You aren't using this but the pattern is the same.
I'd look at how the STL does it. There, you have a sequence (delimited by iterators), a predicate that defines a match and a template function that searches. Since it's a template function, it automatically matches the return values const-qualifiers to that of the parameters.
If, for some reason, you don't want to write a template function, you could also add two overloads, because you can overload functions with different const-qualifiers.
I'd like to answer myself, as the original question was not shaped properly. So, my answer can't be treated as a proper.
There is no legit way to express constness of the input (during the function execution) without forcing a user to not modify the output (and without enforcing the output constness).
A way without _const_cast_:
static Node* findMatchingNode(Node& root, const SomeFilterData& d);
doesn't look like it guarantees the input tree constness.
The original function declaration allows hacks like this, which is also inappropriate:
const Node& root = ...
Node* result = findMatchingNode(root, filter);
result->doBadNonConstThings();

Calling Operator() "function call" to return reference to array element

I think I don't really understand what's behind references, and I'd be glad to learn more about those.
I'm writing a math "vector" Class to do basic linear algeabra for numerical simulation. I was using Eigen before i was convinced not to use external libraries anymore. My problem is pretty straightforward :
I declare vector and sets its 3 components of type Scalar (these are doubles). I can do math with my vectors as I overload operators, but this is beyond the scope of my question.
I want to access the i-th component of my object through the function call operator () as I was used with Eigen : myVector(0) = 0.0 ; or Scalar d = myVector(0)+1.0 ;
According to my understanding of references, this solution should be working :
class mtnVector {
public:
typedef double Scalar;
Scalar data [3];
(setters, math, etc...)
inline Scalar & operator() (const int i) const {
return data[i] ;
}
};
But g++ says that it doesn't like the way I implement it and comfirms I s*** at references :
Vector.h:185: error: invalid initialization of reference of type ?double&? from expression of type ?const double?
What's very strange from my point of view is that if the array containing the data is dynamically set (Scalar * data) (with new operator) at class construction, the code compiles fine. But I don't see the point of having dynamically set data holder.
I don't get neither the need of const to overload the function call operator but I accept it.
Your operator() is declared const. This means that calling the function should never end up modifying the object. That function returns a member of this object by non-const reference, which would allow whoever called operator() to modify the internals of the object. Obviously this would be silly, so the compiler just doesn't allow it. If you're going to return a reference to a member from a const member function, you need to make that reference const:
inline const Scalar& operator() (const int i) const {
return data[i] ;
}
You might want to provide both a const and non-const version of the function, one of which returns a const Scalar& and the other a Scalar& (this is how the standard library containers do it).
It seems strange that you'd want to use operator() for this. Your expression myVector(0) would look more natural as myVector[0], which you can achieve through overloading operator[] instead.
Also, you should ignore whoever convinced you that you shouldn't use external libraries. Eigen, in particular, is a very mature and thoroughly tested library. Unless you really have a good reason, you should be using it.