I was wondering how protect a non const pointer member from an object throught a const method. For example:
class B{
public:
B(){
this->val=0;
}
void setVal(){
this->val = 2;
}
private:
int val;
};
class A{
public:
A():b(new B){}
void changeMemberFromConstMethod() const{
this->b->setVal();
}
private:
B * b; // how to protect data pointed in A::changeMemberFromConstMethod
}
Is it possible to "protect" A::b data pointed from his method?
After many research on web, no satisfied reponse found yet.
Thanks for your help.
Something like this, perhaps:
template <typename T>
class deep_const_ptr {
T* p_;
public:
deep_const_ptr(T* p) : p_(p);
T* operator->() { return p_;}
const T* operator->() const { return p_;}
};
class A {
deep_const_ptr<B> b = new B;
};
deep_const_ptr behaves like a const T* const pointer in A's const methods, and like T* in non-const methods. Fleshing the class out further is left as an exercise for the reader.
If you change the member of A from
B* b;
to
B b;
then you will get the expected behavior.
class A{
public:
A() : b() {}
void changeMemberFromConstMethod() const{
this->b.setVal(); // This will produce a compiler error.
}
private:
B b;
}
The problem you have is that a const method makes all the member variables const. In this case however, it makes the pointer const. Specifically, it's as if all you have is B * const b, which means a constant pointer to a (still) mutable B. If you do not declare your member variable as const B * b, (that is, a mutable pointer to a constant B), then there is no way to protect from this behavior.
If all you need is a const B, then by all means, define A like this:
class A {
public:
A() : b(new B) {}
// This WILL give an error now.
void changeMemberFromConstMethod() const { b->setVal(); }
private:
const B* b;
}
However, if other methods of A mutate B, then all you can do is make sure that B does not get mutated in your const methods of A.
Try using the following general approach, to protect the const-ness of objects referenced via pointers, in this situation.
Rename B *b
B *my_pointer_to_b;
And change the initialization in the constructor accordingly.
Implement two stubs:
B *my_b() { return b; }
const B *my_b() const { return b; }
Replace all existing references to b with my_b(), in the existing code. Going forward, in any new code, always use my_b() to return the pointer to b.
Mutable methods will get a non-const pointer to B; const methods will get a const pointer to B, and the extra step of renaming makes sure that all existing code is forced to comply with the new regime.
Related
I have to work with a tree based hierarchy of objects where I need to access the deepest element that contains the data required by the application. I'm not sure if the previous statement explains in its best the problem itself so its better to present it with an example. Given the following scenario:
class A {
private:
B* _b;
public:
B* getB() {return _b;}
};
class B {
private:
C* _c;
public:
C* getC() {return _c;}
};
class C {
private:
int _n;
public:
int getN() {return _n;}
};
The desired operation would be to access n via A. So I would call the following:
A foo;
foo.getB()->getC()->getN();
The problem comes when any of the parts of the path are null we end up having a core dump. In the above scenario if B is null we end up in a core dump scenario.
Therefore I seek help and advice on any strategy or pattern that I can use to avoid this core dumps scenarios. If the path is extremely big I end up checking every single pointer if its valid and end up having really ugly code and also risk that I might have missed checking a part of the path. Note: I do not have access to change the implementation of the hierarchy of classes (A,B,C) as they are generated code and I do not have access to change the generator. Changing the previous would be my preferred solution but unfortunately I cannot.
In order to avoid having null pointers, you may want to establish a class-invariant that the member is never null. This can be achieved with following steps:
Encapsulate access to the member so that nothing outside the class can set the member. You've already achieved this through the use of private access. Just make sure that you pass/return a reference or a pointer to the member from a member function to the outside.
Ensure that no member nor friend function ever sets the member to null.
Also ensure that the member is always initialised. This is achieved by use of a custom constructor. Example:
class A {
B* b;
public:
A(B* b) : b(b) {
if (!b) {
// unlike indirection through null pointer, an exception can
// be caught and (potentially) handled gracefully at runtime
throw std::runtime_error("Naughty!");
}
}
// following prevents passing null literal at compile time
A(std::nullptr_t) = delete; // nullptr
A(int) = delete; // 0
// since it is never null, we can safely return a reference
B& getB() {return *b;}
}
While references have the nice property of not being ever null, they are tricky as members, since they are also not assignable. As an argument to a constructor, they are tricky since it is generally not conventional or expected for a class object to keep references to objects passed into a constructor. As such, I advocate the use of pointers in this case even when null is undesirable.
Note: I do not have access to change the implementation of the hierarchy of classes (A,B,C) as they are generated code and I do not have access to change the generator.
In this case you may instead wrap the generated classes with better classes:
class AWrapper {
A a;
// custom implementation that encapsulates A
}
If null pointers are valid values that cannot be avoided, then such invariant is of course not possible. In such case, you must always check whether the pointer is null before indirecting through it:
if (B* b = foo.getB())
if (C* c = b->getC())
c->getN();
Another thing that you might consider is whether all these pointers are necessary. Perhaps it would be simpler if the classes contained each other instead of indirectly referring to one another.
You need to test all along the way:
A foo;
B* BPrt = foo.getB();
if (BPrt)
{
C* CPtr = BPrt->getC();
if (CPtr)
{
int n = CPtr->getN();
...
Here's how I solved the problem:
#include <iostream>
using namespace std;
class C {
private:
int _n;
public:
int getN() {return _n;}
};
class B {
private:
C* _c;
public:
C* getC() {return _c;}
};
class A {
private:
B* _b;
public:
B* getB() {return _b;}
};
int main(void);
int main() {
static B b;
static C c;
static A foo;
unsigned int n;
B *bPtr; C *cPtr;
/* --RECODE (CHAIN-CALL): foo.getB()->getC()->getN();-- */
bPtr = (B *) (foo.getB());
cPtr = (C *) (bPtr ? bPtr->getC() : 0);
n = (int) (cPtr ? cPtr->getN() : 0);
/* --USE (CAST) and (TERNARY) instead of (CHAIN-CALL)-- */
cout << n << endl;
return n;
}
If the classes cannot be changed then the checking could be done via a template:
template <typename T, typename A, typename ...Args>
auto recurse(T t, A a, Args... args)
{
if (!t)
throw std::exception{};
auto next = (t->*a)();
if constexpr (sizeof...(Args) > 0)
return recurse(next, args...);
else
return next;
}
Then call as follows:
recurse(&foo, &A::getB, &B::getC, &C::getN);
The problem is not with a pointer being null. That is in-fact good as it mostly crashes at runtime. What if it's not null but has been previously freed/deleted ? The usage will probably lead to Undefined Behaviour.
A better way would be to use references if you can:
class A
{
private:
B& _b;
public:
A(B& b): _b{b} {}
B& getB ()
{
return _b;
}
};
Or something like that. Then you at-least don't have anything dangling (unless you are also using pointers somewhere).
If you have to use pointers then use one of the smart-pointers - see if std::unique_ptr solves if for you. If not then for shared ownership use std::shared_ptr and so on. Also ensure the way you initialise objects don't lead to a default null there.
You can make sure that your pointers are always initialized, if possible:
class C {
private:
int _n = 0;
public:
int getN() {return _n;}
};
class B {
private:
static C default_c;
C* _c = &default_c;
public:
C& getC() {return *_c;}
};
C B::default_c; // An out-of-line static member definition is required.
class A {
private:
static B default_b;
B* _b = &default_b;
public:
B& getB() {return *_b;}
};
B A::default_b; // An out-of-line static member definition is required.
int main() {
A a;
std::cout << a.getB().getC().getN() << '\n';
}
Note that pointers make better members than references because the references break value semantics and make your class non-assignable.
Did you consider:
try {
foo.getB()->getC()->getN();
}
catch(...)
{
//Here you know something is Null
}
That seems the simplest safest,when dealing with existing code.
class B
{
public:
A* GetA() const { return obj; }
private:
A* obj;
}
...
B b;
b.GetA()->AInterfaceMethod(params);
So my questions are:
What would be different had the function not been const?
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
When is this useful?
I encountered this in an Unreal tutorial (A is forward declared in the tutorial).
EDIT: I probably messed up, but the call does work. I've included the actual Unreal code below:
class ABatteryPickup : public APickup
{
ABatteryPickup()
{
GetMesh()->SetSimulatePhysics(true);
}
}
class Pickup
{
public:
class UStaticMeshComponent* GetMesh() const { return PickupMesh; }
private:
class UStaticMeshComponent* PickupMesh;
}
UStaticMeshComponent::SetSimulatePhysics() is not const.
Also, just tested this on a new, clean C++ project, and it works.
What would be different had the function not been const?
If the function is a non-const member function, you can't call it on a const object.
const B b;
b.GetA(); // Fail, can't call a non-const member function on a const object
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
No, nothing is different here. The returned value is not const itself, and not a pointer to const, it's just A* as it declared. If the object is const, the member variable obj will be const too, i.e. A* const, note it's still not a pointer to const, i.e. const A*. Anyway you return it by value with type A*, so nothing is different here.
When is this useful?
Const member function and non-const member function could be overloaded. You might use them for different purpose. e.g.
class B
{
public:
A* GetA() { return obj; } // returns A*
const A* GetA() const { return obj; } // returns const A*
private:
A* obj;
}
...
B b;
b.GetA(); // get A*
const B cb;
cb.GetA(); // get const A*
What would be different had the function not been const?
const method has a contract - it does not change internal state of object B directly or indirectly, for example it would not change pointer obj to point somewhere else. So this code:
A* GetA() const { obj = new A; return obj; }
would fail to compile.
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
No, object of type A is unrelated and to make this method to return pointer of const A you need to change type of the returned pointer:
const A *GetA() const { return obj; } // now you cannot change A through pointer you get, unless you const_cast it.
When is this useful?
You can control separately what you can change inside method and what can be done with object, pointer to which you return. You just have choice.
I'm trying to allow a class to contain a pointer, which may either be an owned pointer or a borrowed pointer. In the former case, it should destroy the owned object itself; in the latter case, it shouldn't destroy the pointed-to object.
In code, I have classes A, B and C. I'm aiming for the following (simplified) definitions, where B is the class that needs to own a pointer:
class C {
...
};
class B {
C *c;
B(C *c) : c(c) {
}
};
class A {
C c1;
B b1, b2;
// b2 leaks pointer to C
A() : b1(&c1), b2(new C()) {
}
};
When an instance of A destructs, it destroys c1, b1 and b2. Ideally, the destruction of b2 should delete the anonymous C instance, but the destruction of b1 should not delete anything (since c1 will be destroyed by A directly).
What kind of smart pointer can I use to achieve this? Or, is the best solution just to pass an ownership flag to B?
If you are sure and can guarantee that the reused C will not be destroyed early (triple check that), there are multiple ways to go about it.
Some you might consider:
You can manually manage the pointer and a flag. Make sure you get the copy-semantic right, e.g. like this:
class B {
std::unique_ptr<C> c;
bool shared = false;
B(C& c) : c(&c), shared(true) {}
B(C *c = 0) : c(c) {}
~B() { if (shared) c.release(); }
};
You could use a custom deleter, like this:
template <class T> struct maybe_delete
{
void operator()(T* p) const noexcept {if(!shared) delete p;}
bool shared = false;
};
template <class T> struct maybe_delete<T[]>
{
void operator()(T* p) const noexcept {if(!shared) delete [] p;}
template <class U> void operator()(U*) const = delete;
bool shared = false;
};
class B {
std::unique_ptr<C, maybe_delete> c;
B(C& c) : B(&c) {this->c.get_deleter().shared = true;}
B(C *c) : c(c) {}
};
You could take a peek at std::shared_ptr, though that is probably severe overkill and might have too much overhead for you.
While I fear for the potential abuse that B is open to, you could do this:
class B {
C *c;
bool owned;
B(C& c) : c(&c), owned(false) {}
B(C *c) : c(c), owned(true) {}
~B() { if (owned) delete c; }
};
class A {
C c1;
B b1, b2;
A() : b1(c1), b2(new C()) {}
};
There is no way to archive this behavior without side effects, as far as I know. If it is just usual pointers (not COM), than you can access C via shared_ptr in both classes. If only B owns C, than they both will be destroyed with B's destroy. If both A & B owns C, than C will be destoyed only when last remaining alive owner (be it A or B) will be destroyed.
I know such practice to think about ownership:
If method gets just a normal pointer, than it is meant that pointer will be used only inside that method. So, B will be:
class B1 {
B(C *c) {
//do some staff with c
}
void doSomeStaff(C*) {}
};
Or using & (cleaner, if your framework accept it):
class B2 {
B(C& c) {
//do some staff with c
}
void doSomeStaff(C&) {}
};
If method gets a shared pointer, it need this pointer for future reuse (keep it):
class B3 {
public:
std::shared_ptr<C> c;
B(std::shared_ptr<C> c) : c(c) {
}
};
So, now you can call b1.doSomeStaff(b3.c) or b2.doSomeStaff(*b3.c) without thinking who must destroy the pointed object C. You know only, that this object will be used in b1. That's all.
Do not forget to specify that you need shared_ptr, not C* in method - shared_ptr is an object, which increments reference count to object when copied. And not increments, but creates a new shared_ptr with reference count = 1, when constructed from C*.
This is not the answer to your question, but some of the common uses. See unique_ptr in Deduplicator's in answer. Also check: http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/smart_ptr.htm. Even if you don't use boost, there is a good theory for using different approaches to hold objects. Also check this answer: What is a smart pointer and when should I use one?
Pass in a unique_ptr via std::move for the owned version and pass in a reference for the unowned version:
no runtime overhead outside a unique_ptr
avoids incorrect usage
avoids having to mess around with custom destructors
no ambiguity
Minimal working example:
#include <iostream>
#include <memory>
class C
{
public:
~C() { std::cout << "Goodbye\n"; }
void SayHello() { std::cout << "Hello\n"; }
};
class B
{
std::unique_ptr<C> owned;
C* unowned;
public:
B(C& c) : owned(nullptr)
, unowned(&c)
{ }
B(std::unique_ptr<C> c) : owned(std::move(c))
, unowned(owned.get())
{ }
C& GetC() { return *unowned; }
};
int main()
{
C stackC;
std::unique_ptr<C> heapC(new C);
B b1(stackC);
B b2(std::move(heapC));
b1.GetC().SayHello();
b2.GetC().SayHello();
}
OUTPUT:
Hello
Hello
Goodbye
Goodbye
I have the code:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test() says "class A", but how I can call method getString() from class B and not A?
Thanks!
The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this
A a;
what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!
To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.
Since a pointer example was already shown by #Nawaz, I will give another using a reference:
class C{
public:
C() : a(b) { // references must be initialized in the constructor initializer list
}
std::string test() {return a.getString();}
private:
B b; // moved to class scope to ensure that it stays alive
A& a;
};
You need to implement like this:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
This will call getString() from class B and not A.
What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).
Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.
You are slicing therefore it will not work. a is an A it is not a B.
To work your class member variable a must be a pointer or a reference.
As a pointer
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
As a reference
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
Of course the code I have produced leaks but will work with the virtual function.
I am not sure whether I am missing something basic. But I am unable to understand why the compiler is generating the error for this code:
class A
{
};
class B
{
public:
B();
A* get() const;
private:
A* m_p;
};
B::B()
{
m_p = new A;
}
A* B::get() const
{
//This is compiling fine
return m_p;
}
class C
{
public:
A* get() const;
private:
A m_a;
};
A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
EDIT: The compiler error is : error C2440: 'return' : cannot convert from 'const class A *' to 'class A *' Conversion loses qualifiers
const in the function signature tells the compiler that the object's members may not be modified. Yet you return a non-const pointer to a member, thus allowing a violation of that promise.
In your class B, you make/break no promise since you don't return a pointer to a member, you return a copy of it (and the member happens to be a pointer).
It's because you're returning a non-const pointer to a member from a const function.
The first part works because you're returning a copy of a member pointer, so this doesn't violate the const-ness of the get function:
class B
{
public:
B();
A* get() const;
private:
A* m_p;
};
A* B::get() const
{
//This is compiling fine
return m_p;
}
But the next bit generates the compile error (on gcc 4)
testfile.cpp:37: error: invalid conversion from ‘const A*’ to ‘A*’
Because your const get function is providing non-const acess to m_a by returning a non-const pointer to it.
class C
{
public:
A* get() const;
private:
A m_a;
};
A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Because the returned pointer is not const. Change it to this:
class C
{
public:
const A* get() const;
private:
A m_a;
};
const A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Notice that C::get() now returns a const pointer to A.
Member functions marked const cannot return a non-const reference or pointer to a private variable. If the compiler allowed this, anyone outside your class would be able to modify the said private variable and the const qualifier on the function would lose meaning.
This problem can be illustrated with a simpler example:
class MyClass {
public:
int *get() const;
private:
int value;
};
int *MyClass::get() const {
return &value;
}
In MyClass::get() const, value has the type const int. When you dereference it, you get const int *. That type cannot be safely (implicitly) casted to int *. To correct your problem, have get() return const int *.
A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Because get() is a const function, the compiler treats all member variables it refers to as const. When you take the address of such a member, you get a pointer to const. But your function is returning a non-const pointer. You need to change your code to
const A* C::get() const
{
return &m_a;
}
Basically just add a const in front,
const A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Then if you want to access it, basically do:
C something;
const A* a = something.get();
However, your program makes very little sense, to me.
IMO, it would make most sense to do:
class A{
};
class C : public A
{
};
That way you don't have to make a "get" that returns the instance of A.