I need to implement read-only access to a private member container. If I return a constant reference is it possible to const_cast it and obtain a full access to the member? What's the technique to be used?
Thanks.
I need to implement read-only access to a private member container. If I return a constant reference is it possible to const_cast it and obtain a full access to the member? What's the technique to be used?
Thanks.
const int &ref = your_object.your_function();
*(int*)&ref = 1234;
Yes as long as the lifetime of the reference does not exceed the lifetime of the object which returned it. If you must expose the private member you do not want modified, this is a good way to do so. It's not foolproof but it's one of the better ways to do so in C++
Yes and there is nothing you can do to prevent this. There is no way to prevent someone from casting away const in C++ at any time. It's a limitation / feature of C++.
In general though, you should flag every use of const_cast as a bug unless it contains a sufficiently detailed comment as to why it's necessary.
Yes, so it's probably not what you want to do. On the other hand, if someone is going to the trouble of const casting your reference, it's possible they really know what they are doing.
*const_cast* can be definitely used to obtain the full access to the member. I guess you can not stop people if they are hell bent on shooting themself on the foot. If the private member is not heavy, consider returning a copy of that variable.
It is possible to obtain a full access. But what for?
Don't forget to make accessor to be const correct
const MyType& getMyValue() const;
Also you can inject you private value in the callback.
void doJob( callback c )
{
c( myPrivateValue_ );
}
Returning a const & is a sensible thing to do in many circumstances, particularly if the object being returned is large or cannot be copied.
Regarding the const_cast, remember the "private" access specifier in C++ is there as an aid to the programmer - it is not intended to be a security measure. If someone wants access to an object's private members, it can get them, no matter what you try to do to prevent it.
Don't worry about users doing const_casts just to break your invariants. If they really want to break your code they can without you providing accessors to your internal attributes. By returning a constant reference, the common user will not mistakenly modify your data.
Encapsulation prevents mistakes, not espionage A malicious coder can break it anyway if they really care and know the environment (compiler). Const-ness is lost in the compilation process (in all compilers I know of). Once the compilation unit is converted into binary objects, those objects do not know about const-ness, and that can be exploited to take advantage.
// a.h
class A
{
public:
A( int a ) : data_( a ) {}
A get() const { return data_; }
private:
int data_;
};
// malicious.h
class A;
void change( A& a, int new_value );
// malicious.cpp
// does not include a.h, but redefines an almost exact copy of it
class A {
public:
A( int a ) : data_( a ) {}
int get() const { return data_; }
int data_; // private removed
};
void change( A& a, int new_value )
{
a.data_ = new_value;
}
// main.cpp
#include "a.h"
#include "malicious.h"
int main()
{
A a(0);
change( a, 10 );
std::cout << a.get() << std::endl; // 10
}
While the code above is incorrect (One definition rule is broken, there are two definitions for class A), the fact is that with most compilers the definition of A and malitious A are binary compatible. The code will compile and link, and the result is that external code has access to your private attributes.
Now that you know of it, _**don't do it**_. It will later be a maintenance pain in the ***. That has cost Microsoft quite a bit of money in providing backwards compatibility to software that used private parts of the API returned objects (new versions of the API that shared the same public interface but changed the internals would break some third party application code). With some broadly available software the provider (Microsoft in this case) will go through the pain of providing backwards compatibility, but with lesser known applications they won't and suddenly your previously running application will fail in all sort of ways.
I think it was Herb Sutter that once said that one should "Protect against Murphy, not against Machiavelli." That is, you should do everything possible to protect against the code being used incorrectly by accident, but there's nothing you can do about people abusing your code on purpose.
If someone really wants to break your code, they can, even if it's by #define private public
before including your header (and thus creating an ODR violation, but I digress).
So yes, passing back a const ref is fine.