class Foo
{
public:
const int a;
const int* x;
int* const y;
Foo() : a{ 0 }, y{ new int(20) } {
x = new int(10);
}
};
int main()
{
Foo f;
// f.a = 100; // cannot
f.x = new int(100);
// f.y = new int(100); // cannot
}
When const int a is defined as fields of a class,
it is called a constant member. It must be initialized in the initializer list and cannot be changed afterwards.
How about const int* x (which is the same as int const* x) and int* const y? Which one should be called as a constant member? If "constant member" is defined as field that must be initialized in the initializer list and cannot be changed afterwards, then the constant member is y rather than x. Am I wrong here?
Edit
According to IntelliSense, y is a constant member.
OK. I am sure I am not wrong. I will delete this question shortly. Thank you for your participation!
The "const int* x" is a (non-const) pointer to a const int. Since x is non-const, it need not be initialized upon construction.
Here are some examples:
class C
{
public:
C() :
const_int(1),
const_int_again(2),
const_ptr_to_non_const_int(nullptr),
const_ptr_to_const_int(nullptr)
{}
private:
const int const_int;
int const const_int_again;
const int* ptr_to_const_int; // Doesn't need initialized
int const* ptr_to_const_int_again; // Doesn't need initialized
int* const const_ptr_to_non_const_int;
const int* const const_ptr_to_const_int;
int const* const const_ptr_to_const_int_again;
};
You may find the cdecl.org website helpful.
Related
Imagine that I have an object A that refers to an object B through its address. The address to B is given in the constructor of A.
Some methods of A modify B, other do not.
Here is a very simple illustration :
class B {
public :
void f1() const;
void f2();
};
class A {
public :
A(B * pb) {m_pb=pb;}
void g1() {m_pb->f1();} // g1 do not modify *m_pb
void g2() {m_pb->f2();} // g2 do modify *m_pb
private :
B * m_pb;
}
Now, imagine that in some part of my code, I have a variable whose type is const B &. I want to create an object A to call the g1 method that do not modify the object B. But I cannot construct an object A at all.
One solution would be to create 2 classes A1 and A2 with A1 referencing a const B * and defining only method g1 while A2 would reference a B * and would define both g1 and g2. (g1 would be defined in 2 different places). I don't find this solution very elegant.
I wonder whether there is a way to explain to the compilator that :
const A won't modify the object B that it is referring.So a const A objet can be constructed using a const B object.
I wonder whether there is a way to explain to the compilator that : const A won't modify the object B that it is referring.So a const A objet can be constructed using a const B object.
What you want is const constructor and there isn't one. But you can avoid duplicating the interface with inheritance:
struct B{
void f1() const{}
void f2() {}
};
class constA
{
public:
constA(const B* b):b(b){}
// Should be const as it does not changes `constA` object.
void g1() const {b->f1();}
// No harm in this, but can be protected if you want
const B* getB() const { return b;}
private:
const B* b;
};
class A : public constA
{
public:
A(B* b):constA(b){}
void g2() const { getMutableB()->f2();}
private:
B* getMutableB() const { return const_cast<B*>(getB());}
};
int main()
{
B b;
const B cb;
A a(&b);
a.g2();
a.g1();
constA ca(&cb);
ca.g1();
//ca.g2();
constA ca2(&b);
ca.g1();
//ca.g2();
}
EDIT: (Per request from #formerlyknownas_463035818 with which I agree ) Quick refresher on const_cast:
int main()
{
const int x = 5;
int y = 5;
const int* c_ptr = &x;
//'ptr' is valid object with known value.
int* ptr = const_cast<int*>(c_ptr);
// Is valid because '*ptr' is not modified
int value = *ptr;
// Undefined behaviour because '*ptr' is const object.
*ptr = 5;
const int* c_ptr2 = &y;
//'ptr2' is valid object with known value.
int* ptr2 = const_cast<int*>(c_ptr2);
// Is valid because '*ptr2' is not modified
int value = *ptr2;
// Is valid because '*ptr2' is not a const object.
*ptr2 = 5;
}
Given that A only has non-const B constructor then getB() always returns a pointer to a object that is not const. So the second part of the above example applies and everything is safe.
Note that const casting const B in order to pass it to A would produce UB when calling g2 but that is true for all B* ptrs with unknown origin and there's nothing A class can do about it.
Does the following program have undefined behavior?
#include <iostream>
#include <vector>
struct Foo
{
const std::vector<int> x;
};
int main()
{
std::vector<int> v = {1,2,3};
auto f = new Foo{v};
const_cast<int&>(f->x[1]) = 42; // Legal?
std::cout << f->x[1] << "\n";
}
Note that it not using const_cast to strip constness from f->x, but instead stripping constness from f->x[x], which presumably is represented by a separate array. Or is a translation allowed to presume that f->x[1] is immutable after it is created?
There is no Undefined Behavior in your example.
The above code does not invoke undefined behavior because the underlying data (int) is mutable. Let's look at a simpler example.
#include <iostream>
struct IntPtr {
int* data;
};
int main() {
int a = 0;
const IntPtr p { &a };
*p.data = 10;
std::cout << a; // Prints 10
}
All of this is perfectly legal to do because making IntPtr const results in data being a constant pointer to an int, NOT a pointer to a constant int. We can modify the data that p.data points to; we just can't modify p.data itself.
const IntPtr p { &a };
*p.data = 10; // This is legal
int b;
p.data = &b; // This is illegal (can't modify const member)
So how does this example apply to std::vector?
Let's add the ability to index into an IntPtr:
class IntPtr {
int* data;
public:
IntPtr() = default;
IntPtr(int size) : data(new int[size]) {}
// Even though this is a const function we can return a mutable reference
// because the stuff data points to is still mutable.
int& operator[](int index) const {
return data[index];
}
};
int main() {
const IntPtr i(100);
i[1] = 10; // This is fine
};
Even though the IntPtr is const, the underlying data is mutable because it's created by allocating an array of mutable ints. It's the same for std::vector: the underlying data is still mutable, so it's safe to const_cast it.
This question already has an answer here:
Unable to initialize private const member [duplicate]
(1 answer)
Closed 4 years ago.
Why can't I do this in C++?
struct SomeStruct
{
public:
SomeStruct(const int someInt)
{
m_someInt = someInt;
}
private:
const int m_someInt;
};
Should the private field just be a regular integer?
You're assigning someInt to m_someInt, which is illegal. But initialization is okay.
struct SomeStruct
{
public:
SomeStruct(const int someInt) : m_someInt(someInt)
{
}
private:
const int m_someInt;
};
More info: Constructors and member initializer lists
Value cannot be assigned to a const storage. It can be only initialized. In case of class member variable it would be done in initialization list.
struct SomeStruct
{
public:
SomeStruct(const int someInt) : m_someInt(someInt)
{
}
private:
const int m_someInt;
};
Sometimes in-class initialization is enough:
template <int Val>
struct SomeStruct
{
public:
private:
const int m_someInt = Val;
};
Usually confusion stems from the fact that programmer doesn't see difference between two cases:
// 1) Declaring storage of int object that initially contains value 5
int a = 5; // It's a declaration.
// 2) Declaring storage of int object that contains undetermined value
int b; // Declaration
b = 5; // Assigning a value to it. It's a statement.
In your case m_someInt = someInt; is a statement that expects lvalue before =, and m_someInt is not a legal lvalue because it is const.
I didn't find any topics related to mutable const on SO. I have reduced code to minimal working code (on visual studio). If we uncomment //*data = 11;, the compiler complains about const-ness. I wonder how mutable const works.
class A
{
public:
void func(int & a) const
{
pdata = &a;
//*pdata = 11;
}
mutable const int * pdata;
};
int main()
{
const A obj;
int a = 10;
obj.func(a);
}
This example is a little confusing, because the mutable keyword is not part of the type specifier const int *. It's parsed like a storage class like static, so the declaration:
mutable const int *pdata;
says that pdata is a mutable pointer to a const int.
Since the pointer is mutable, it can be modified in a const method. The value it points to is const, and cannot be modified through that pointer.
You are correct in understanding that a mutable const class member is meaningless. Your example is more demonstrating a quirk of how const works with pointers.
Consider the following class.
class A {
const int * x; // x is non-const. *x is const.
int const * y; // y is non-const. *y is const.
int * const z; // z is const. *z is non-const.
};
So const has different meanings depending on where you write it.
Since x and y are non-const, there's no contradiction in making them mutable.
class A {
mutable const int * x; // OK
mutable int const * y; // OK
mutable int * const z; // Doesn't make sense
};
mutable const sounds like an oxymoron, but it actually has a perfectly sensible explanation. const int * implies that the pointed-to integer value cannot be changed through that pointer. mutable means that the pointer itself can be changed to point to another int object, even if the A object to which the pdata member belongs it itself const. Again, the pointed to value can't be changed through that pointer, but that pointer itself can be reseated.
Your code fails when the assignment statement is uncommented because that assignment violates your promise not to modify the pointed to value (the const int * part).
How do I make G::t static? (e.g., G::t should be of type const static int&) G::t is defined by the constructor parameter p and not available anywhere else.
class G {
public:
// I want to make this static.
const int& t;
G(const int& p);
};
G::G(const int& p) : t(p) {}
int main() {
int a=2;
const int& b = a;
G g = G(b);
}
e.g.:
const int a = 10;
class foo
{
static const constexpr int& t = a;
};
You can't initialize static member in constructor, because constructors are for objects, not for class as whole.
Why are you even using a constructor if you want to set static members to be used by static functions? That's not what constructors are for. You definitely can't initialize a static member in an initializer-list, because that would mean it got initialized every time you constructed another object. (Just think about the difference between per-class static data and per-instance data and it should be obvious why the question makes no sense).
You could use a static local, which is initialized on first use so can be initialized at run-time, and then can be accessed by the static member functions:
class G {
public:
static int t(const int& p = 0, bool set = false);
G(const int& p);
};
G::G(const int& p) { t(p, true); }
int G::t(const int& p, bool set)
{
static bool is_set = false;
if (!is_set)
{
if (!set)
throw std::logic_error("Cannot use G::t before it is set");
}
else if (set)
throw std::logic_error("Cannot set G::t more than once");
static const int tt = p;
set = true;
return tt;
}
int main() {
int a=2;
const int& b = a;
G g = G(b);
int t = G::t();
}
But this is a horrible hack, you should think carefully about your design and whether using a constructor is appropriate here, or even if using a class is appropriate.
The member initializer list can only be used to initialize instance variables, so if t is static, you can only reassign it in the constructor body.
And because references can't be reassigned, you have to use a pointer. A reference_wrapper doesn't work because it would need to be statically initialized (unless you have a global int that you can use for that).
E.g.
class G {
public:
static const int* t;
G(const int& p);
};
const int* G::t; // definition in .cpp
G::G(const int& p) {
t = &p;
}