Let's say I have a class:
class A{
B* b;
public:
A(B* pb):b(pb){}
}
And I make sure const method of A never modify the object pointed by b. So that it is safe to hold B const* when instance of A is const.
B const b;
A a(&b); // compile error
A const ca(&b); // compile error too. How can I allow this one
This is impossible—constructors can’t even tell if the object is (going to be) const, let alone control overload resolution with the information.
The standard workaround (often used for iterators) is to make A a template (even if it only ever has two specializations) and use A<const B> to handle that case. Yes, this is pretty poor: partly because it can delay some diagnostics, but more because there’s no automatic conversion from A<B> (nor can a const A<const B>& bind to an A<B>). The good news is that this works without any special effort even when A has methods that do mutate b (which are often const in this formulation); they won’t be instantiated unless used.
Related
I have a class which contains references, like:
class A {
A(B &b) : b(b) {} // constructor
B &b;
}
Sometimes b must be read-only, sometimes it is writeable. When I make a const A a(b); object, it's obvious that I want to protect the data inside it as const.
But - by accident - it's easy to make a non-const copy of the object which will make the data inside it vulnerable.
const A a(b); // b object protected here
A a_non_const(a);
a_non_const.b.non_const_function(...); // b not protected now
I think that I should somehow prevent copies of the object when it is const like this:
const A a(b);
const A a2(a); // OK!
A a_non_const(a); // Compiler error
Is this possible at all?
flaw in your code: your data isn't "protected" even with const
The const type qualifier manages access to the member functions of a type as well as the access to its members. Since your member B & b is a reference, const doesn't do much for you here: A reference cannot be changed after initialization either way. How you access the target of that reference isn't even considered:
const A a(b);
a.b.non_const_function(); // OOPS, no problem!
solution with templates
Instead of (ab)using the const type qualifier you could add a "flag" to your type, to differentiate between cases where you need to be able to have non-const access and case where you don't:
#include <type_traits>
struct B {
void danger() {
}
void all_fine() const {
}
};
template<bool Writeable>
struct A {
using BRef = typename std::conditional<Writeable, B &, B const &>::type;
BRef b;
A (BRef b) : b(b) {};
};
using ConstA = A<false>;
using NonConstA = A<true>;
int main() {
B b;
ConstA a(b);
//NonConstA nc_a(a);
ConstA another_a(a);
//another_a.b.danger();
another_a.b.all_fine();
NonConstA a2(b);
a2.b.danger();
}
With some std::enable_if you can then selectively enable / disable member functions of A depending on whether they need "writeable" b or not.
real solution: refactor your design
BUT I'd like to highlight this comment even more:
"Sometimes b must be read-only, sometimes it is writeable." All your problems stem from this weird duality. I suggest picking one set of semantics for your class, not two
From Lightness Races in Orbit
You should probably instead consider splitting your class such that you have a CommonA with functionality used by both a WriteableA and a NonWriteableA (the names are terrible, but I hope you understand what I mean).
You can do it for the heap:
static const A *constCopy(const A &a); // and of course implement it somewhere
Then you will not accidentally modify the object via the pointer you get (which has to be stored in const A *, otherwise the compiler will complain).
However it will not work with stack-based objects, as returning const A & of a local variable is a rather deadly action, and "const constructor" has not been invented yet (related: Why does C++ not have a const constructor?)
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>.
I keep running into the same problem when designing data-observing classes (like iterators), regarding the handling and conversion of their const and non-const versions.
Consider a class which observes some externally handled data via a pointer or similar (similar to std::weak_ptr):
template<typename T>
class observer {
public:
observer(T* ptr) :
_ptr(ptr) {}
T& get() const {
return *_ptr;
}
private:
T* _ptr;
};
This is all cool and dandy, except for when you want only const access to the observed data:
template<typename T>
void need_const(observer<T const>) {}
// Uh oh...
observer<int> o{ nullptr };
need_const(o); // Can't do
One obviously loses the implicit conversions to const versions like with all the fundamental types (int -> int const, T* -> T const* etc). I have several ideas for how to work around this, but none of them seem ideal, and I was wondering what a good C++-style solution to this problem would be.
A converting constructor for observer<T> accepting an observer<U>. Would work fine for some cases (and is in fact what is used in std::weak_ptr), except that it creates a new object, obviously. It wouldn't work for anything wanting to access the object via an lvalue reference, such as
template<typename T> void need_const(observer<T const>&) {}.
Instead using two classes, observer<T> and const_observer<T> which have non-const and const pointers, respectively, to the observed data. This is similar to how the standard library does iterators. This still doesn't solve the problem mentioned in the above point, leading to more options of how to design it:
observer<T> contains a const_observer<T>, using const_casts to allow non-const access, and implementing an operator const_observer<T>&() for conversion for const access. Works perfectly, except the use of const_cast feels dodgy and inelegant to me.
observer<T> inherits from const_observer<T>, using const_casts to allow non-const access. Again, this works perfectly, except it introduces inheritance, which is another whole kettle of fish to deal with.
Something I haven't considered.
Below C++11 code won't compile (should work to my first impression) under g++ 4.9.2:
class A{};
class B : public A{};
void func(shared_ptr<B>){}
TEST(testFunc, testFunc_conv){
std::function<void(shared_ptr<A>)> afunc;
afunc = func;
}
The error messages indicate it doesn't accept the conversion from shared_ptr<B> to shared_ptr<A> though those B can be converted to A.
Why doesn't this work? Is it possible to work around this limitation?
EDIT
I consider the implications carefully and understand the reason - A can't be converted to B indeed, so it's not allowed for the sake of type safety.
The background of this code is to implement some generic interface with variadic parameters, so other part of the world can register a callable that taking derivatives of an empty base type. The callable would be called later (kind of deferred call):
//action would be stored for deferred call
// when action is actually called, it will use the real type
template<class ObjType>
registerInterface(function<void(Base*)> action, ObjType* obj){
function<void()> callable = [=]{ action(obj);}
//callable action would be stored for deferred call
}
void interfaceImpl(Derived* d){
d->realOperation();
}
//do registration - need to do the conversion each time for each interface implementation!
Derived d;
registerInterface(interfaceImpl, &d);
It would be annoying for each interfaceImpl to declare as taking the base type and do the downcasting brutely.
My solution is to remove the function from interface and set a implicit callable template argument for interfaceImpl to specify. Appreciate if there're better solutions.
If you want polymorphism, the declaration should include the parent class so you are able to pass its a children into it.
You are using a specific child in the definition, then trying to use the function with the base one. Obviously this would not work.
Either inherit from B or change the declaration to use the class A.
Note:
I am pretty sure you can do what you are trying to achieve in C++. However, the question you should ask yourself is: "Just because I can, should I really do it?" For example, just because you can abuse pointers to retrieve a private member of a class does not mean you should do it, and making an accessor will nearly always be the better choice.
Remember, code is being much more often read and reviewed than written. I would much rather see a straightforward code, than reading a pice of code including special constructs of the language just to make it work.
shared_ptr<B> is convertible to shared_ptr<A>. The buck stops here. Types below are not convertible:
shared_ptr<B>* to shared_ptr<A>*
void(*)(shared_ptr<B>) to void(*)(shared_ptr<A>)
function<void(shared_ptr<B>)> to function<void(shared_ptr<A>)>
This is for a good reason. What happens in the next fragment?
func (new A); // should not compile
afunc = func; // imagine this is allowed
afunc(new A); // now what?
Some of the conversions above but in the opposite direction do make sense, but C++ doesn't allow them for a number of historical and other reasons.
Fortunately you don't need any of this. You can do
template<class ObjType>
registerInterface(function action, ObjType* obj)
Or, better
registerInterface(std::function<void()> func) ...
And then call
register_interface(std::bind(funcA,objA));
register_interface(std::bind(funcB,objB));
You write "those 2 types are convertible". They are not.
Since B is a subtype of A, B can be assumed to hold additional members. Therefore it is not allowed to do what you are trying. You are saying specifically that func needs a ptr to B to operate on.
Then you create a function pointer that clearly states you will send something of type A. This can not work, because as stated B being the derived class may contain more members than A, members upon func may depend (since it specifies it explicitly as the argument type).
The other way around is polymorphically ok though. You could pass type B where type A is expected, because A being the base type, this would make it certain that B has the same members, thus it is safe to pass it (since it is of type A).
Given a declaration like this:
class A {
public:
void Foo() const;
};
What does it mean?
Google turns up this:
Member functions should be declared with the const keyword after them if they can operate on a const (this) object. If the function is not declared const, in can not be applied to a const object, and the compiler will give an error message.
But I find that somewhat confusing; can anyone out there put it in better terms?
Thanks.
Consider a variation of your class A.
class A {
public:
void Foo() const;
void Moo();
private:
int m_nState; // Could add mutable keyword if desired
int GetState() const { return m_nState; }
void SetState(int val) { m_nState = val; }
};
const A *A1 = new A();
A *A2 = new A();
A1->Foo(); // OK
A2->Foo(); // OK
A1->Moo(); // Error - Not allowed to call non-const function on const object instance
A2->Moo(); // OK
The const keyword on a function declaration indicates to the compiler that the function is contractually obligated not to modify the state of A. Thus you are unable to call non-const functions within A::Foo nor change the value of member variables.
To illustrate, Foo() may not invoke A::SetState as it is declared non-const, A::GetState however is ok because it is explicitly declared const. The member m_nState may not be changed either unless declared with the keyword mutable.
One example of this usage of const is for 'getter' functions to obtain the value of member variables.
#1800 Information: I forgot about mutable!
The mutable keyword instructs the compiler to accept modifications to the member variable which would otherwise cause a compiler error. It is used when the function needs to modify state but the object is considered logically consistent (constant) regardless of the modification.
This is not an answer, just a side comment. It is highly recommended to declare variables and constants const as much as possible.
This communicates your intent to users of your class (even/especially yourself).
The compiler will keep you honest to those intentions. -- i.e., it's like compiler checked documentation.
By definition, this prevents state changes you weren't expecting and can, possibly, allow you to make reasonable assumptions while in your methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
If you're using a language with static, compile time checks it's a great idea to make as much use of them as possible... it's just another kind of testing really.
Functions with const qualifier are not allowed to modify any member variables. For example:
class A
{
int x;
mutable int y;
void f() const
{
x = 1; // error
y = 1; // ok because y is mutable
}
};
C++ objects can be declared to be const:
const A obj = new A();
When an object is const, the only member functions that can be called on that object are functions declared to be const. Making an object const can be interpreted as making the object readonly. A const object cannot be changed, i.e. no data members of the object can be changed. Declaring a member function const means that the function is not allowed to make any changes to the data members of the object.
Two suggested best practices from experience:
(1) Declare const functions whenever possible. At first, I found this to be just extra work, but then I started passing my objects to functions with signatures like f(const Object& o), and suddenly the compiler barfed on a line in f such as o.GetAValue(), because I hadn't marked GetAValue as a const function. This can surprise you especially when you subclass something and don't mark your version of the virtual methods as const - in that case the compile could fail on some function you've never heard of before that was written for the base class.
(2) Avoid mutable variables when it's practical. A tempting trap can be to allow read operations to alter state, such as if you're building a "smart" object that does lazy or asynchronous i/o operations. If you can manage this with only one small mutable variable (like a bool), then, in my experience, this makes sense. However, if you find yourself marking every member variable as mutable in order to keep some operations const, you're defeating the purpose of the const keyword. What can go wrong is that a function which thinks it's not altering your class (since it only calls const methods) my invoke a bug in your code, and it could take a lot of effort to even realize this bug is in your class, since the other coder (rightly) assumes your data is const because he or she is only calling const methods.
const has a funny way of propagating through your code. Thus, it's a really good idea to start using const as early and as often as possible. Deciding to start const-ifying your code late in the game can be painful (easy, but annoying).
Additionally, you will easily run into problems if methods that should be const aren't! This will creep through the code as well, and make it worse and worse.
that will cause the method to not be able to alter any member variables of the object