Consider the sample code below:
class A
{
public:
A() : n(0) {}
int n;
};
class B
{
public:
B(A* a) : mA(a) { }
B(const A* a) : mConstA(a) { }
union {
A* mA;
const A* mConstA;
};
};
int main()
{
A a;
B b1(&a);
B b2(const_cast<const A*>(&a));
return 0;
}
At construction, b1 would have a mutable pointer to a, while b2 would have an immutable pointer to a. In this scenario, b1.mA equals b2.mConstA, and b1.mConstA equals b2.mA.
Are these equalities always true when you have a union of const and non-const object pointers?
Similarly, the code below compiles/runs fine:
int main()
{
const A a;
B b(&a);
b.mA->n = 3; // Blasphemy!!!
return 0;
}
But is it guaranteed for b.mA to always be equal to b.mConstA?
Are these equalities always true when you have a union of const and non-const members?
Yes, both pointers will refer to the same object in the same address. The bits in memory will be the same.
But is it guaranteed for b.mA to always be equal to b.mConstA?
Yes, their values will be the same, but that does not mean that you can really use it. This is equivalent to using const_cast, you will get a non-const pointer to the object, but if the object is really const, using that pointer to modify the object is undefined behavior.
Related
I got a situation where I have a class B having a protected array of A*. I have an another function A* func() which returns pointers to A objects stored in some other container. (for example std::map<int,A*> or A* arr[]).
For example the following implementation:
#include <iostream>
using namespace std;
class A {
public:
A(int _x): x(_x){};
int x;
};
class B{
public:
B() {
this->arr[0] = new A(1);
this->arr[1] = new A(2);
}
// use idx to index in to the internal array and return A*
A*& operator[](int idx); // return reference to pointer to avoid not a lvalue error
private:
// class B has this private array of A*
A* arr[2];
};
A*& B::operator[](int idx) {
return this->arr[idx]; // 0<=idx<=1
}
A* arr[2];
A* func(int x) {
return arr[x]; // 0<=idx<=1
}
int main() {
arr[0] = new A(12);
arr[1] = new A(14);
B b;
b[1] = func(1); // assign a new value
cout << b[1]->x << endl; // prints 14
}
// memory leaks of this program can be removed using `std::shared_ptr<A>` in the place of `A*`.
In this example, operator[]() returns a reference to a pointer, because returning pointer becomes rvalue and I will not be able to assign value to it (i.e. b[1] = func(1)).
My question is, is this reference to pointer returning recommended (other ways to achieve this )? or is this perfectly fine with raw pointers as well as with shared_ptr?
Thank You!
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.
I have a function getA() which returns a const reference of base type A, since it's const, it cannot dynamic_cast it, so I make a copy of the const reference and then created a reference to the copied object, but when I call dynamic_cast to the reference of the copied object, it fails, the code is shown below:
struct A {
int c = -1;
virtual ~A() {}
};
struct B : A {int aa = 0;};
const A& getA(){
std::unique_ptr<A> ap(new B);
return *ap;
}
int main()
{
const A& a = getA();
A acopy = a;
acopy.c = -2;
A& acopyr = acopy;
std::cout << a.c << std::endl;
try{
B& b = dynamic_cast<B&>(acopyr);
std::cout << b.aa << std::endl;
}catch(std::bad_cast b){
std::cout << "bad" << std::endl;
}
}
The output is
-1
bad
acopy is an object of dynamic (and static) type A. Notice how it was declared: an object of type A. So of course it cannot be cast to a B&.
From your description, I take it you just want to dynamically cast getA() to a const reference to B. There's nothing stopping you from that:
const B& b = dynamic_cast<const B&>(getA());
Side note: I assume the getA implementation in your question is just for demonstration purposes, but it's very wrong. As soon as ap goes out of scope (that is, as soon as getA returns), it will destroy the object to which it points, so you're returning a dangling reference and thus invoking Undefined Behaviour.
Suppose I have a class A, whose constructor requires an argument x.
class A
{
public:
int a;
A(int x) { a = x; std::cout << a << std::endl; }
~A() {}
};
Now I want to allocate an array of A, and wrap it in another class B (in reality it should be a 2-dimensional array of A, mapped onto a 1-dimensional array, which is why I need to wrap it). Since constructor of A requires argument, I cannot use new[] (…right?), so I have to have an A**. Also I don’t want B to know about x, so my B is like this:
class B
{
private:
A** As;
const int n;
public:
B(int nn): n(nn) { As = new A*[n]; }
~B() { delete[] As; }
A* at(int i) { return As[i]; }
const A* at(int i) const { return As[i]; }
};
Note that “subscription operator” loosely means that at() function. Now my main function is like this:
int main()
{
B b(3);
int x = -1;
for(int i = 0; i < 3; i++)
{
b.at(i) = new A(x);
}
return 0;
}
When I compile this with g++, it prints an error “lvalue required as left operand of assignment” at my “new” line. Then I change my signature of at() to
A*& at(int i)
and it works.
What’s bothering my is that A*&, which just looks weird to me…
Is this A*& something I should use? Or any other way to deal with an array of objects, whose constructor requires arguments? BTW we don’t have c++11 and boost available on our target machine…
"Or any other way to deal with an array of objects, whose constructor requires arguments?"
Use std::vector, you don't need C++11 for it, neither any additional libraries:
#include <vector>
...
std::vector<A> myObjects(n, A(0)); // objects will be constructed by calling A(0)
Your class B could look the following way:
class B
{
private:
std::vector<A> As;
const int n;
public:
B(int n): n(n), As(std::vector<A>(n, A(0))) { }
// no explicit destructor needed
// memory management is handled by std::vector object automatically
A& at(int i) { return As[i]; }
const A& at(int i) const { return As[i]; }
};
Note that vector's elements are stored within continuous block of memory and lifetime of these elements is tied to the lifetime of instance of B. Once the B is destructed, so is the vector and so are the elements that were stored in it. If n is a constant known at compile time, you might also consider using std::array instead.
The & operator has a role to change an function parameter or a return variable to a reference.
Without & the value of the variable will be copied into a temporal variable, therefore the original variable will not be sensible to any value changes.
By referenced handling the parameter will be the original variable only the name differs, but signs the same memory block.
In this example the b.at(i) statement will be copied into a temporary constant variable, which is unusable in the left side of = statement.
But by referenced return of this statement it points to the original As[i] memory block, only the 'name' differs, and so can be changed its value too.
Why does the following code not allow foo(ptr) to be called ?
#include <boost/scoped_ptr.hpp>
struct A {
virtual ~A() {}
};
struct B: public A {};
void foo(boost::scoped_ptr<A>& a) {}
void goo(A& a) {}
int main() {
boost::scoped_ptr<B> ptr(new B);
foo(ptr);
B b;
goo(b);
}
The corresponding form where we pass references works as expected. Are we supposed not to do polymorphism
with boost scoped_ptr ?
g++ with boost 1.49 gives me:
error: invalid initialization of reference of type ‘boost::scoped_ptr<A>&’ from expression of type ‘boost::scoped_ptr<B>’
That's because foo, for some reason, takes a scoped pointer by reference. That is completely unnecessary and is the reason why the call fails. There is a conversion from scoped_ptr<B> to scoped_ptr<A> but not from scoped_ptr<B>& to scoped_ptr<A>&.
You should pass it as reference to const.
void foo(boost::scoped_ptr<A> const & a) {}
Incidentally, this isn't a "problem" of smart pointers per se. The following code fails for the same reasons as yours.
void foo(A*& p) {}
int main()
{
B* p = new B;
foo(p); //FAIL
}
In order to fix this you have to pass the pointer either by value, or, if you're sufficiently perverted, by reference to const
void foo (A * const & p); // <-- a perv wrote this