As far as I read here and there, const should be used when possible. However, I have a case that always bothers me.
Should I mark a member function as const when it does not alter any member variable values but it is not conceptually a const function?
For example:
class Engine{
public:
int status;
};
class Car{
public:
void start() const{
engine_->status = 1;
}
private:
std::unique_ptr<Engine> engine_;
};
The compiler will accept the constness of start() since engine_ as a pointer did not change. However, It seems so unrealistic, at least IMO, that a function called start in a class called Car is a const one!
The example was just a quick one. Usually, some internal states of the Car class should be updated accordingly making const keyword non-feasible. However, the mini example was just to illustrate my idea.
One simple metric for whether a function should be const is this:
Type a{...};
Type b{...};
bool comp1 = a == b;
b.some_func(...);
bool comp2 = a == b;
If comp1 and comp2 can ever be different, then some_func is not const.
Obviously, not every type has an operator== overload, but most have at least the conceptual idea of what you would test to see if they're equal. Different Car instances with different engine states would be unequal. Therefore, a function that changes the engine state is not const.
In your case compiler allows you to make start() const due to imperfect propagation of constness through pointers. If you replace your pointer with object of type Engine your question will disappear. So answer is no, it should not be const in this case as using Engine as a smart pointer or instance is internal details and should not affect public interface of class Car.
As far as I read here and there, const should be used when possible.
This statement is way too generic, and as with any generic suggestion should not be used formally in every case.
In your example, you might want std::experimental::propagate_const:
class Car{
public:
void start() { engine_->status = 1; }
private:
std::experimental::propagate_const<std::unique_ptr<Engine>> engine_;
};
Then your start can no longer be const.
The meaning of const can vary.
Something is const if it preserves ==.
Something is const if your type follows reference semantics and it doesn't change what is referred to.
Something is const if it can be used on any rvalue or lvalue in sensible ways.
Something is const if it is safe to use from multiple threads.
Something is const if it compiles as const.
Something is const if whatever state the object claims is internal is not mutated by it.
All of these are reasonable rules to decide if a method or argument is or is not const.
A thing to be extremely careful of is to know the difference between T const* and T*const, and don't accidentally hse top-level const as an internal const. It isn;t const iterator it is const_iterator. It isn't const gsl::span<int>, it is gsl::span<const int>. It isn't const unique_ptr<T>, it is unique_ptr<T const>.
On the other hand, vector is a value semantics typr; it pretends its buffer is a part of it (even though this is a lie). It isn't vector<const T>, it is const vector<T>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With