Bitiwise Const and pointers: - c++

I read a line in Meyers:
"A member function that modifies what a pointer points to frequently doesn`t act const.
But if only the pointer is in the object, the function is bitwise const, and compilers wont complain."
I fail to understand that modifying a pointer in a function cannot maintain its bitwise constantness since its a member variable...
Even if we assume that bitwise constantness is only for values that pointers point to and not for the pointer addresses themselves..
Then why does it matter if its the only member variable in the class or if its not the only only member variable..

Basically this means that if you had
struct Foo
{
int bar;
};
you couldn't have a const member function change the value of bar.
However if bar is a pointer to an int, you could change the value of the int in a const method because the int is not actually part of the struct.
Both versions achieve the same goal (i.e. change the value of the int) but in the first version you are breaking bitwise constness and the compiler will complain, in the second it wont.

It's bitwise const because the member function only
modifies what [the] pointer points to
so the object instace data (the member pointer) doesn't change only the object on the heap that it points to.

Take the following simple classes:
class A
{
public:
A(int d = 0) : data(d) {}
void func() const
{
++data; // Can't do this. That's changing
// the bitwise content of this.
}
private:
int data;
};
And
class B
{
public:
A(int d = 0) : data(new int(d)) {}
void func() const
{
++(*data); // Can do this. That doesn't change
// the bitwise content of this.
}
private:
int* data;
};

If I read it correctly, a member function usually isn't qualified const if it modifies a value pointed at by a pointer stored in the current object:
class A {
char* string;
public:
void UpCaseString() { strupr(string); }
....
}
The UpCaseString() method modifies data which 'belong' to the object, so it usually would not be declared as const. However it actually modifies some buffer allocated outside the current object, the instance of A class has only a char* pointer to the buffer—so the buffer can still be modified even when the object itself is const:
class A {
char* string;
public:
void UpCaseString() const { strupr(string); }
....
}
void foo(A const &a) {
a.UpCaseString();
}
Member a.string is not modified here.

Related

Pass Interface object to constructor c++?

Say i have an interace like
#include<iostream>
struct Interface
{
virtual void fun() = 0;
};
struct IType : Interface
{
void fun() override
{
std::cout<<"non const fun()";
}
};
class Type
{
private:
Interface &intr; // I can't declare intr as const i need to ascess non const fun()
public:
// I put it as a const for default value
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)} // Is const_cast is safe or how to do it ?
// What is god idea to do it should i need to remove const and default value but i need a default constructor
{
intr.fun();
}
};
int main()
{
Type obj;
return 0;
}
Thanks.
Reference as class member is rarely a good idea. You need an object, passed from the outside, that will outlive your class object. You cannot use default argument and you cannot use a temporary for initialization. Typically, if you need to pass different types that inherit from an interface, this is solved with (smart) pointers.
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)}
//Is const_cast is safe or how to do it ?
It depends. You can cast away constness only if the real object is not const. So this:
IType itype{};
Type {itype};
would be valid, but this:
const IType itype{};
Type {itype};
would be invalid.
Your default argument is invalid anyway, because that default is a temporary object that dies immediately once constructor finishes, which means you cannot use intr member outside of this constructor.
I'm not 100% sure if const_cast is valid on temporary or not, but that doesn't matter in this case.
The solution is to use (smart) pointers:
class Type
{
private:
std::shared_ptr<Interface> intr;
public:
Type(std::shared_ptr<Interface> obj = std::make_shared<IType>()) : intr{std::move(obj)}
{
intr.fun();
}
};
The default choice for smart pointer is std::unique_ptr, but use of reference suggests that you wanted access to object from the outside of the class as well, and std::shared_ptr will allow that.

Calling non-const function of another class by reference from const function [duplicate]

This question already has answers here:
Why can I call a non-const member function pointer from a const method?
(5 answers)
Closed 3 years ago.
Imagine the following example:
class A
{
public:
void doSomeStuff() { std::cout << "SomeStuff" << std::endl; }
};
class B
{
public:
B(A& a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A &a;
};
If doSomeStuff() would change the data, wouldn't that affect class B as well? Why is such behaviour allowed?
If doSomeStuff() would change the data, wouldn't that affect class B as well?
Well, not in the way a compiler checks for const correctness. A B holds a reference to an A. That object can reside anywhere, but most importantly it doesn't reside inside the B object. So modifying it does not do something with undefined behavior like changing a const object. We have a reference to a non-const object, so it's possible to modify the object via the reference. That's as far as the C++ type system cares, whether or not the object is maybe physically const.
It will probably affect the logical state of the B, but it is the responsibility of the programmer to ensure the class invariants hold. C++ will not hold your hand in that endeavor.
The original object of the class A will be changed.
When you are using a const member function then the function deals with const T *this where T is the class type.
That is data members of the object are considered constant.
For a referenced type it could look like
A & const a;
However references themselves can not be constant.
That is for example this declaration
int x;
int & const rx = x;
is invalid and does not mean the same as
const int & rx = x;
So the class B has a reference that points to a non-constant object and using the reference the object can be changed.
Compare with the following declaration of the class B
class B
{
public:
B(A * a) : a(a) {}
void constStuff() const { a.doSomeStuff(); }
private:
A *a;
};
Then then a constant member function is used the data member is considered like
A * const a;
(pointers themselves may be constant) that is the pointer itself that is constant not the object pointed to by the pointer and you can not change the pointer itself but you can change the object pointed to by the pointer.
The const-qualified this pointer that's present in a const-method protects data changes from members inside B. B holds a reference to A so the object a references does not reside inside B and thus changes are allowed. This const qualification of this does not pass on to the reference.
If you would want to avoid that, you're supposed to make the reference to the helper class const:
class B
{
public:
B(const A& a) : a(a) {}
void constStuff() const { /* Invalid call: a.doSomeStuff(); */ }
private:
const A &a;
};

Passing a shared pointer by reference or by value as parameter to a class

Should a shared pointer be passed by reference or by value as a parameter to a class if it is going to be copied to a member variable?
The copying of the shared pointer will increment the refrence count and I don't want to make any unnecessary copies and thus ref count increments. Will passing the shared pointer as a refrence solve this? I assume it does but are there any other problems with this?
Passing by value:
class Boo {
public:
Boo() { }
};
class Foo {
public:
Foo(std::shared_ptr<Boo> boo)
: m_Boo(boo) {}
private:
std::shared_ptr<Boo> m_Boo;
};
int main() {
std::shared_ptr<Boo> boo = std::make_shared<Boo>();
Foo foo(boo);
}
Passing by refrence:
class Boo {
public:
Boo() { }
};
class Foo {
public:
Foo(std::shared_ptr<Boo>& boo)
: m_Boo(boo) {}
private:
std::shared_ptr<Boo> m_Boo;
};
int main() {
std::shared_ptr<Boo> boo = std::make_shared<Boo>();
Foo foo(boo);
}
Pass it by value then move it into the member:
class Foo {
public:
Foo(std::shared_ptr<Boo> boo)
: m_Boo(std::move(boo)) {}
private:
std::shared_ptr<Boo> m_Boo;
};
This will be the most efficient in all cases - if the caller has a rvalue-reference then there wont be a single add-ref, if the caller has a value there'll be a single add-ref.
If you pass by const& you force an add-ref even in cases where its unnecessary. If you pass by value and then set without a std::move you may get 2 add-refs.
Edit: This is a good pattern to use if you've got a class where a move is significantly cheaper than a copy, and you have a function call which will always copy the instance passed in - as in this case. You force the copy to happen at the function call boundary by taking it by value, and then if the caller has a rvalue reference the copy need never happen at all - it will be moved instead.
shared_ptr should be treated just like any other class when passing to functions.
in this case you should pass to const reference.
why i wrote why i wrote Herb Sutter jump to min 21:50
https://www.youtube.com/watch?v=xnqTKD8uD64

const correctness and member pointers

I have const on the Accelerate method, yet I can call the power method. Is their a way to actually stop this.
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine* p;
};
For Car, a const method is a methods which does not modify Car member variables.
so, as long that Car::Accelerator does not make p point to a different location, it is valid.
since p is not modified in Accelerator (meaning it does not point to a different memory address), the program is valid.
the moment you make p point to a different location, the program fails to compile:
void Accelerator() const {
p= nullptr; //wrong
}
Const protection affects only the direct members, in this case the pointer only. Values outside this object (aka. pointed values) are not protected.
You have to decide if you consider the pointed value as yourself or someone else.
You can modify the member Engine as const*, which will make the Engine object pointed to by p in Car const:
class Engine{
public:
void Power(){
}
};
class Car{
public:
Car() : p(new Engine()){}
void Accelerator() const{
p->Power();
}
private:
Engine const* p;
};
This will no longer compile:
test_const.cpp:12:9: error: member function 'Power' not viable: 'this' argument
has type 'const Engine', but function is not marked const
p->Power();
^
test_const.cpp:3:10: note: 'Power' declared here
void Power(){
^
But this implies that no member of Car can modify *p, which is probably not what you intend. See #NathanOliver's comment for better answer.
Hope this helps.

calling class function inside other class function c++

My program is working fine and does what its supposed to do but the notation used doesn't seems right to me. I have a class with some variables and two functions:
foo.h
class foo{
private:
int a;
public:
void seta1(int value);
void seta2(int value);
};
foo.cpp
void foo::seta2(int value)
{
a = value;
}
void foo::seta1(int value)
{
seta2(value);
}
then when i print variable a it has the value its supposed to have, but wouldn't this notation be more correct?
void foo::seta2(int value)
{
this.a = value;
}
No. this is a pointer, not a reference.
this->a = value would be correct.
The this-> is implied in this case (a a non-static member being accessed in a non-static member function). There are some circumstances where the this-> is required, but this is not one of them.
actually it should be this->a, since this is a pointer. however you don't need to usually write "this" since it's implied. both are correct.
This is only useful if a member variables is over-ridden by a local variable.
For example:
void foo::seta2(int a)
{
this->a = a;
}