Would it be possible for a public function to return a pointer to a private variable in the class. If so / if not, what would happen? would it crash or is there anything highly unsafe about this? Can the pointed data be read or written to?
Thanks
Yes, a member function may return a pointer (or reference) to a private data member. There is nothing wrong with this except that in most circumstances it breaks encapsulation.
The data member can certainly be read via the returned pointer or reference. Whether or not it can be written to depends on whether the returned pointer or reference is to a const-qualified object (i.e., if you return a const T*, you won't be able to modify the pointed-to T). For example:
class Example
{
public:
int* get() { return &i; }
const int* get_const() const { return &i; }
private:
int i;
};
int main()
{
Example e;
int* p = e.get();
int a = *p; // yes, we can read the data via the pointer
*p = 42; // yes, we can modify the data via the pointer
const int* cp = e.get_const();
int b = *cp; // yes, we can read the data via the pointer
*cp = 42; // error: pointer is to a const int
}
Yes it can be returned and it can be read and written to. It is no more or less dangerous than taking the address of any other variable. Public/private/protected are syntactical constructs that are checked at compile time, and they aren't "contagious" or part of the type of something.
A private member is no different from a public member, or any other type of instance. So, yes, you can take pointers to them, and return them.
When taking pointers to any instance-based member, you have to be careful that the parent class is not deleted and doesn't go out of scope, unless you take that pointer and make a true copy of the data/object it points to. If it is deleted or goes out of scope, the pointer becomes a dangling pointer, and you can't use it anymore without your app exploding (or working on non-existent objects, and thus making your program do crazy unexpected things, but not crashing).
Design considerations:
Exposing any of your internal implementation details is potentially a violation of encapsulation. However, if you only want to encapsulate HOW the object you're returning is created/retrieved, then this is a reasonable solution. This would allow you to change the class to get the member object some other way (like querying a file, or an internal dictionary) without breaking code that calls these methods.
"would it crash or is there anything highly unsafe about this? Can the pointed data be read or written to?"
private/protected/public have no effect whatsoever at runtime, so they can't influence the program execution or even crash the program. They are checked at compile time and just cause your compiler to throw an error while compiling if there is a violation.
The const qualifier won't protect you on those cases. Considering James's response, please try to cast the const int * to int *
int* cp = (int*)e.get_const();
You will still be able to modify.
Related
When overloading operator ->, one would eventually have to return a pointer. If this pointer points to an object created inside the function like:
struct Something {
char c;
Something(char k){
c = k;
}
};
struct Hello {
int a;
Something* operator->(){
Something s(a);
return &s;
}
};
Would then dereferencing this result in undefined behavior (as Can a local variable's memory be accessed outside its scope?):
Hello h {5};
cout << h->c;
If so, can this be resolved, still using operator->?
Would then dereferencing this result in undefined behavior?
Yes.
If so, can this be resolved, still using operator->?
The following applies to any other member function.
Create Something instance as a member of Hello. Then the pointer to it remains valid for the duration of Hello's lifetime. You can construct Something from the integer you are storing immediately, so you can get rid of it.
If Something takes additional resources (memory, handles, etc.), you probably want to construct it at the time of operator-> call. You can choose std::unique_ptr (dynamic) or std::optional (static) for this. Or, if Something supports an uninitialized state (e.g. default-constructed), you can initialize (e.g. move-assign) to it later.
If you cannot alter Hello class then your only option is to overload operator-> to return by Something by value directly.
But, I must say, the circumstances of this problem are starting to get weird and the way of overloading operators even more so.
I would like to ask a question about methods' const-correctness. Let me illustrate the situation.
class MyClass
{
public:
...
void DiscussedMethod() { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
I have a class MyClass which keeps a pointer to OtherClass. In DiscussedMethod it calls OtherClass::NonConstMethod which modifies some visible data.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)? Would it be a bad practice? Or is both fine?
What if the OtherClass kept a pointer to the MyClass and in NonConstMethod modified some of the MyClass' data (meaning that the MyClass member data would change during the DiscussedMethod call). Would it be a bad practice to make the DiscussedMethod const then?
As far as I've been able to find out, the const on a method is mostly a code documenting thing, so I would probably lean toward to not making the DiscussedMethod const, but I would like to hear your opinions.
EDIT: Some replies take the into account whether the object pointed to by otherClass is owned by the MyClass object. This is not the case in the scenario I'm working with. Lets say that both objects exist independently side by side (with the ability to modify each other). I think this analogy describes my situation quite well.
For example consider something like doubly-linked list, where each element is a class that keeps pointer to its neighbours and member variable color. And it has method MakeNeighboursRed which changes the color of its neighbours but doesn't affect the calling object's state itself. Should I consider making this method const?
And what if there was some possibility that MakeNeighboursRed would call neighbour's MakeNeighboursRed. So in the end the state of the object for which MakeNeighboursRed has been called originally would change as well.
And I would like to thank you all for your opinions :-)
If MyClass owns the OtherClass instance i wouldn't make DiscussedMethod constant.
The same goes for classes, managing resources. I.e. the standard containers do not return non const references or pointers to the managed memory using const functions, although it would be "possible" (since the actual pointer holding the resource is not modified).
Consider
class MyClass
{
public:
bool a() const { return otherClass->SomeMethod(); }
void b() const { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
void foo (MyClass const &x)
{
cout << boolalpha << x.a() << endl;
x.b(); // possible if b is a const function
cout << boolalpha << x.a() << endl;
}
The foo could print two different values although an implementor of foo would probably expect that two function calls on a const object will have the same behaviour.
For clarification:
The following is invalid according to the standard since the const version of operator[] returns std::vector<T>::const_reference which is a constant reference to the value type.
std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a
It would be possible if there was only one signature of this function, namely referece operator[] (size_t i) const;, since the operation does not alter the internal pointers of the vector but the memory they point to.
But the memory, managed by the vector is considered to be part of the vectors state and thus modification is impossible through the const vector interface.
If the vector contains pointers, those pointer will still be unmodifiable through the public const vector interface, although the pointers stored in the vector may well be non const and it may well be possible to alter the memory they point to.
std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *
In OOP object should be fully described by its state, available through its interface. Thus, const methods should not alter object's state, if these changes might be observed through the interface.
A good example is a mutable mutex inside your class to guard some shared resources. It might be modified from const method, since it does not introduce any changes observable via class interface.
General rule of thumb is, that if you can make a member function const, you probably should. The reason for that is that it allows you to catch unintended behaviour and bug easier.
Another argument in favor would be that if you have this function as const you are allowed to call it on const object, so it isn't really a documentation thing.
Overall it depends what the other class is. It's not black and white...
If otherClass is a log object (for example) and you want to log the operation of the current object then it's perfectly fine calling it from a const function.
If the otherClass is a container that for design (or implementation) purposes is implemented as a separate object than effectively a const function modifies the object making this a very bad idea.
I hope this helps.
It's totaly incorrect to make DiscussedMethod const as it changes it's *this state. The only loophole to this is making non-logically-part-of-object's-state member data mutable so they can be changed in const functions. This would be things like a member that hold a count for "number of times function x() has been called". Any thing else is part of the object's state, and if a function changes it (at any level), that function isn't const.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)?
otherClass is member data, and it (or rather, the object it points to) gets modified.
Consider the semantics should the pointer to otherClass be refactored to a fully-owned object... whether something is held as a pointer, reference, or object doesn't change the semantical ownership, IMO.
In following example const object can modify itself via const method, because in that method it acces itself via non-const pointer. (same program on ideone)
#include <iostream>
struct Object;
Object * g_pObject;
struct Object
{
Object():m_a(0){}
void ModifySelfViaConstMethod() const
{
g_pObject->m_a = 37;
}
int m_a;
};
int main()
{
Object o;
g_pObject = &o;
const Object & co = o;
std::cout << co.m_a << "\n";
co.ModifySelfViaConstMethod();
std::cout << co.m_a << "\n";
return 0;
}
I am not so good with reading c++ standard, so I ask here:
What does standard says about this?
a)const method doesn't guarantee you that your object stays unmodified when you do stuff like this
b) Is it well defined that and it must compile
c) other ?
When you declare a const function, it's "for your own good".
In other words, you declare it const because according to your initial design, it is not supposed to change any object with which it will be invoked during runtime.
If during some later point in the implementation of this function you end up changing the object, the compiler will "yell at you", telling you it's wrong.
Of course, the compiler will be able to identify such attempt, only when applied on this.
In the given example, the compiler cannot identify the problem because it requires a comparison between this and g_pObject, and such comparison can only take place during runtime.
When a method is declared as const, the compiler ensures that the instance pointed to by the this pointer is not modified. If you try to modify the this instance, the compiler to fail. However, the compiler has no way of knowing that g_pObject and this are actually pointing at the same instance. That requires a run-time comparison, and no compiler is going to waste time performing run-time comparisons of every pointer used inside of a const method in the off-chance that they might match the this pointer. So if you are going to modify an Object via an external pointer, you are going to have to do your own check, eg:
void ModifySelfViaConstMethod() const
{
if (g_pObject != this)
g_pObject->m_a = 37;
}
What does standard says about this?
It says (paraphrasing) that this has type const Object *, so that you can't directly modify members or call non-const member functions via this. It says nothing about what you can do with any global variables that the function might have access to; it only controls direct access to the object the function is called on.
const method doesn't guarantee you that your object stays unmodified when you do stuff like this
No it doesn't. It states the intent that the function won't modify the object, and provides some protection against accidentally breaking that intent. It doesn't prevent a suitably deranged programmer from using const_cast, or (as here) uncontrolled coupling via global variables to break the promise.
Is it well defined that and it must compile
Yes. o is not itself constant, so there's nothing to stop you taking a non-const pointer or reference to it. The const on the member function only restricts access to the object via this, not to arbitrary objects via other pointers.
Constancy in C++ is a safety instrument, not security.
The code where constancy is honored will most probably work as expected, and all unintentional attempts to cast constancy away will be alerted by the compiler.
In cases when "I know what I am doing" one can find the whole variety of tools, from const_cast operator and mutable keyword to the banal C style cast.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why isn't the const qualifier working on pointer members on const objects?
Consider the following class that has a pointer member int *a. The const method constMod is allowed by the compiler even though it modifies the pointer data. Why doesn't the compiler make the pointer data const in the context of the const method? If a was just an int we wouldn't be allowed to modify it in a const method.
class ConstTest
{
public:
ConstTest(int *p): a(p) {}
void constMod() const {
++(*a);
}
int *a;
};
I'm using g++ on linux.
Inside constMod(), the declaration of a is treated as:
int *const a;
which means the pointer has a constant value, not what it points to. It sounds like you are expecting it to be treated as:
const int *a;
which is different.
The pointer itself is not modified, only the data pointed. Even if it sounds strange from a human point of view, from a compiler point of view, none of the member of the class are altered.
It's just an ownership issue... there's no way the compiler can know if the pointed-to object is logically part of the object or not, so it's left for the programmer to police such issues. const members are allowed to perform operations with side effects, as long as they don't modify their own apparent value. It's not really any different from letting them call say std::cout::operator<<() or some other non-const function....
What is const in the above case is the pointer itself. You are not allowed to do ++a;. However, it doesn't prevent you from modifying the data being pointed to.
I believe because here you are trying to change the value where datamember is pointing to.
If you try to modify the data member it would be error.
Meaning, you'll get error if you make a point to something else instead of changing the value
const member functions will not allow you to modify it's members.
In your example, you have a pointer that points an int.
And in the const method, you are modifying the value that it is pointed to but not the pointer itself.
Try giving, ++a, which will actually modify the pointer value and will not be allowed in your const method.
Consider
const T immutable_object0;
const T immutable_object1;
const T* mutable_view = ...a condition... ? &immutable_object0 : &immutable_object1;
// then later you reseat
mutable_view = ...another condition... ? &immutable_object0 : &immutable_object1;
or
const int immutable_data[120]
const int* mutable_view = immutable_data;
for(const int* end = immutable_data + 120; mutable_view != end; ++mutable_view) {
// can't modify *mutable_view
}
It's because pointers don't always have ownership. In some circumstances pointers are views to an object (first example) or are iterators into a raw array (second example). For those cases it doesn't make sense to restrict the operations available on the pointers just because the data pointed to is immutable (or seen as immutable).
The first example is a bit contrived but a valid version of it is when you use a pointer member to implement object association and you don't want the hassle of a reference member. Sometimes the pointed-to types happen to be const.
Given the following code:
class foo;
foo* instance = NULL;
class foo
{
public:
explicit foo(int j)
: i(j)
{
instance = this;
}
void inc()
{
++i;
}
private:
int i;
};
Is the following using defined behavior?
const foo f(0);
int main()
{
instance->inc();
}
I'm asking because I'm using a class registry, and as I don't directly modify f it would be nice to make it const, but then later on f is modified indirectly by the registry.
EDIT: By defined behavior I mean: Is the object placed into some special memory location which can only be written to once? Read-only memory is out of the question, at least until constexpr of C++1x. Constant primitive types for instance, are (often) placed into read-only memory, and doing a const_cast on it may result in undefined behavior, for instance:
int main()
{
const int i = 42;
const_cast<int&>(i) = 0; // UB
}
Yes, it is undefined behavior, as per 7.1.5.1/4:
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
Note that object's lifetime begins when the constructor call has completed (3.8/1).
This may be one of the rare cases where the not very known mutable keyword could be used:
mutable int i;
i can now be changed even if the object is const. It's used when logically the object doesn't change, but in reality it does.
For example:
class SomeClass
{
// ....
void DoSomething() { mMutex.lock(); ...; }
mutable Mutex mMutex;
}
In DoSomething() the object doesn't logically change and yet mMutex has to change in order to lock it. So it makes sense to make it mutable, otherwise no instance of SomeClass could be const (assuming you lock the muetx for every operation).
If you define a const instance of the object, then cast away the const-ness, and modify the contents of the object, you get undefined behavior.
From the sound of things, what you want is exactly the opposite: create a non-const instance of the object, then return a const pointer to that object to (most of) the clients, while the "owner" retains a non-const pointer to the object so it can modify members as it sees fit.
You'd typically manage a situation like this by defining the class with a private ctor, so most clients can't create objects of the type. The class will then declare the owner class as a friend, so it can use the private ctor and/or a static member function to create instances (or often only one instance) of the object. The owner class then passes out pointers (or references) to const objects for clients to use. You need neither a mutable member nor to cast away constness, because the owner, which has the "right" to modify the object, always has a non-const pointer (or, again, reference) to the object. Its clients receive only const pointers/references, preventing modification.
Calling a non-const (by declaration) member function on a const object is not illegal per se. You can use whatever method you wish to work around the compiler restrictions: either an explicit const_cast or a trick with constructor as in your example.
However, the behavior is only defined as long as the member function you are calling does not make an attempt to actually physically modify the object (i.e. modify a non-mutable member of the constant object). Once it makes an attempt to perform a modification, the behavior becomes undefined. In your case, method inc modifies the object, meaning that in your example the behavior is undefined.
Just calling the method, again, is perfectly legal.
It's hard to tell the intent with these arbitrary names. If i is intended as just a use counter, and it isn't really considered part of the data, then it is perfectly appropriate to declare it as mutable int i; Then the const-ness of an instance is not violated when i is modified. On the other hand, if i is meaningful data in the space being modeled, then that would be a very bad thing to do.
Separately from that, though, your example is a bit of a mess for what you seem to be asking. foo* instance = NULL; is effectively (if confusingly) using a NULL as a numeric zero and initializing instance, which is not const; then you separately initialize f, which is const, but never reference it.
Under GCC, at least, your constructor should be explicit foo(int j) with the word int.
However, it's perfectly fine to have two pointers to the same value, one const and the other not.
Why dont you make use of const cast ?
Any reason to make object as const eventhough its state is not constant?
Also make following change :
explicit foo(int j = 0) : i(j)
{ instance = this; }