User defined conversion assigned to const ref variable via temporary object - c++

The code below is a simplified version of the actual problem I am facing.
Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.
The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.
How do I prevent or make it legal in this case so that the caller gets the correct A value?
class A
{
public:
A() { }
A(int _r, int _g, int _b)
: r(_r), g(_g), b(_b)
{
}
~A(){ }
int GetR() const { return r; }
int GetG() const { return g; }
int GetB() const { return b; }
private:
int r = 0;
int g = 0;
int b = 0;
};
class Foo
{
public:
Foo() : Foo(A()) {}
Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
explicit Foo(const A& _a) : a(_a) {}
Foo& operator=(const A& a)
{
*this = Foo(a);
return *this;
}
operator A() const { return a; }
operator const A&() const { return a; }
private:
A a;
};
int main()
{
const A& a = Foo(200, 100, 300);
std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope
return 0;
}
Motivation
Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.
There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.

You can apply ref-qualified member functions (since C++11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).
class Foo
{
public:
... ...
operator A() const { return a; }
operator const A&() const & { return a; }
operator const A&() && = delete;
... ...
};
Then
const A& a = Foo(200, 100, 300); // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()

Related

How to code operation overload so it operates to a specific class member such as A<<{{1,2,3},{5,6,7}} in c++?

You can redefine operator << in class by overload it.
However, how do you code it so that it would operates specific to a certain class member?
for example
class C
{
int a;
double b;
}
// I would like something like
void main ()
{
C c;
c.a << 1; // sets class member a to value 1;
}
I want a operator defined in Class C that operates specifically to class member a.
a pesudo-code would be
class C
{
int a;
double b;
void operator << (istream & fin)
{
... fin.get()... some code
}
}
Stating the obvious for a moment, assuming the variable is public, you'd use:
class C
{
int a;
double b;
}
// I would like something like
void main ()
{
C c;
c.a = 1; // sets class member a to value 1;
}
The << and >> operators are bit shifts, which have their own meaning. Overloading those for your own purpose is probably a bad idea.
The C++ way of doing things is to avoid setting member variables externally where possible (e.g. using RAII approaches, to set data at initialisation)....
class C
{
public:
C(int a, double b) : a(a), b(b) {}
int getA() const { return a; }
double getB() const { return b; }
private:
int a;
double b;
};
.... Or by adding a setter method if you really need it, e.g.
class C
{
public:
C(int a, double b) : a(a), b(b) {}
int getA() const { return a; }
double getB() const { return b; }
void setA(int v) { a = v; }
void setB(double v) { b = v; }
private:
int a;
double b;
};
You could in theory generate a new type, and overload the operators for that type, but it's not something I'd recommend (because changing the meaning of an operator is almost always a bad idea)
struct MyIntType {
int i;
// overload cast operator
operator int () {
return i;
}
// assign
MyIntType& operator = (const int& v) {
i = v;
return *this;
}
// not recommended :(
MyIntType& operator << (const int& v) {
i = v;
return *this;
}
};
class C
{
public:
MyIntType a;
double b;
};
void main ()
{
C c;
c.a << 1;
}
Having read your comment above, it sounds like you want to do this:
class C
{
public:
// I'm still not recommending this :(
C& operator << (const int& v) {
a = v;
return *this;
}
private:
int a;
double b;
};
void main ()
{
C c;
c << 1; //< now sets c.a
}

C++ compilation error: cannot convert from B to A, no constructor, or constructor overload ambiguity

I have some code which implies a type conversion, which does not compile although there is a conversion method...
class A
{
public:
A(void) :_m(0) { }
A(int val) : _m(val) {}
private:
int _m;
};
class B
{
public:
B(void) : _m(0) {}
B(int val) : _m(val) {}
B(const A&);
// there is a direct conversion operator here
operator A(void) const { return A(_m); }
operator int(void) const { return _m; }
private:
int _m;
};
int main()
{
B b;
A a = (A)b; // error C2440 here
}
Here is the error message:
error C2440: 'type cast': cannot convert from 'B' to 'A'
message : No constructor could take the source type, or constructor overload resolution was ambiguous
The error message means that these two operators
operator A(void) const { return A(_m); }
operator int(void) const { return _m; }
can be used in the expression
(A)b;
As a result using these conversion operators there can be used either the constructor A( int ) or the default copy constructor A( const A & ).
To make it more clear rewrite the corresponding declaration like
A a = A( b );
So whether the object b is converted to an object of the type A using the first conversion operator or to an object of the type int using the second conversion operator.
You could avoid the ambiguity declaring the operators for example like
operator A(void) const & { return A(_m); }
operator int(void) const && { return _m; }
that is for lvalues the first operator will be used and for rvalues the second operator will be used.
Here is your program with the modified operators.
#include <iostream>
class A
{
public:
A(void) :_m(0) { }
A(int val) : _m(val) {}
private:
int _m;
};
class B
{
public:
B(void) : _m(0) {}
B(int val) : _m(val) {}
B(const A&);
// there is a direct conversion operator here
operator A(void) const & { return A(_m); }
operator int(void) const && { return _m; }
private:
int _m;
};
int main()
{
B b;
A a = b;
A a1 = B();
}
From what I understand, the compiler tries several paths to interpret a = (A)b.
it finds the operator A
but it also finds the operator int on B, and the A(int) constructor which gives it a second path B => int => A...
And it does not know which to pick.
To fix the compilation, I can:
remove the operator int from B
rewrite the error line as A a = b.operator A();...

Passing a const reference down a chain of constructors

I get a runtime error with the following code, which is a reproducible reduction of my actual code. I am sure I am not instantiating something properly, but I cannot figure out what it is.
#include <iostream>
using namespace std;
class A {
int n;
public:
A();
A(const int k);
int getn() const { return n; };
};
A::A() : n(0) {};
A::A(const int k) : n(k) {}
class B {
const A& myA;
public:
B(const A& anA);
int getn() const { return myA.getn(); };
};
B::B(const A& anA) : myA(anA) {}
class C {
const A& myA;
const B& myB;
public:
C(const A& anA);
int getn() const { return myB.getn(); };
};
C::C(const A& anA) : myA(anA), myB(myA) {}
class D {
A myA;
C myC;
public:
D(const int k);
int getAn() const { return myA.getn(); };
int getCn() const { return myC.getn(); };
};
D::D(const int k) : myA(k), myC(myA) {}
int main() {
D myD(10);
cerr << "A: " << myD.getAn() << '\n';
cerr << "C: " << myD.getCn() << '\n';
}
I either get a segmentation fault on the second line of output or "C:0", instead of "C:10" which I expect.
The problem is in this line:
C::C(const A& anA) : myA(anA), myB(myA) {}
myB is a reference. But to what? The answer is to a temporary. myB(myA) will construct a temp object that is assigned to your reference. Unfortunately this object will be destroyed after the Ctor exits.
Change your code to the following:
class C {
const A& myA;
const B myB;
public:...
and it should work.
BTW: I nearly always declare constructors with one argument as explicit. Do so and the compiler will warn you.
You are trying to initialize D::myC with reference to D::myA, this is not correct because object is not completely constructed at this moment.
D::D(const int k) : myA(k), myC(myA) {}

`shared_ptr` breaks constness of the object

Consider the following code:
class B
{
int x;
public:
B() : x( 10 ) {}
int get_x() const { return x; }
void set_x( int value ) { x = value; }
};
class A
{
boost::shared_ptr<B> b_;
public:
boost::shared_ptr<B> get_b() const { return b_; } // (1)
};
void f( const A& a)
{
boost::shared_ptr<B> b = a.get_b();
int x = b->get_x();
b->set_x( ++x ); // (2)
}
int main()
{
A a;
f( a );
return 0;
}
In this code (2) compiles without any errors or warnings independently the fact that get_b is a const function and a is a const object.
My question is how do you deal with this situation? The best I could use is to change (1) to the following:
boost::shared_ptr<const B> get_b() const { return b_; } // (1)
But I should always remember that I should add const to the return type. That's not very convenient. Is there a better way?
This doesn't actually have anything to do with shared pointers per se. I mean if you had a plain pointer you'd have exactly the same problem and would solve it in exactly the same way, that is
const B* get_b() const {return b_; }
If you left it like
B* get_b() const {return b_; }
you'd have the same problem.
Well, you have found the solution yourself.
boost::shared_ptr<const B> get_b() const { return b_; } // (1)
It's the only const-correct way to do it.

Elegant way to force vector elements having same properties

The title is a bit vague but I can't come up with a better wording, here's the deal:
class A
{
public:
A();
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
SetPropertyB( const PropertyB& b );
//assignment not allowed
};
Suppose I want to use an std::vector< A >, but, it only makes sense to have a vector of A if all it's elements have the same value for PropertyB. The current solutions is to supply a contrcutor-like method to create such array which guarantees all elements of the returned array have the same value for PropertyB, and a method that checks if that is the case:
Array MakeArray( size_t, const PropertyB& );
bool CheckIfArrayIsSane( const Array& );
So users can still call SetPropertyB() on the elements, but have a utility to check it and bail out if someone did:
Array x( MakeArray( 3, someValue ) );
x.SetPropertyA( aaa ); //should be allowed
x.SetPropertyB( someOtherValue ); //should NOT be allowed
//somewhat further in the program
if( !CheckIfArrayIsSane( x ) )
throw InsaneArrayExcpetion();
While this works, it's error-prone since it is hard to force this check everywhere and not forget it, and clutters the code with checks.
Approcahes that do not work:
Making SetPropertyB() private, and making MakeArray a friend function: then SetPropertyB() is not accessible anymore for users that simply want to use A without caring about the array.
Wrapping std::vector< A > in a seperate class and only returning const A& references: this would mean the other setters like SetPropertyA() can also not be called, but users should be able to call them. It's only SetPropertyB() that should be disallowed.
One more intrusive approach that would work but feels a bit unelegant, and needs extra functions to convert between the two etc:
class AWithFixedPropertyB
{
public:
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
};
class A : public AWithFixedPropertyB
{
public:
//contrcutors etc
SetPropertyB( const PropertyB& b );
};
//ok, users cannot modify property B in this Array
typedef std::vector< AWithFixedPropertyB > Array;
What would be the most elegant solution for this problem?
This doesn't make sense, from an OO design viewpoint. Remember the Liskov Susbsitution Principle: A is-a B whenever an A object can be used in the place of a B object? Per that rule, the elements of your proposed std::vector<A> fail the is-an-A test, since you can't set their B property. Yet std::vector<A> is supposed to be a container of A objects.
In C++ we have private inheritance, and this makes explicit that the derived class does not have an is-a relationship with its parent. You can use that as follows:
class A_fixed_B : private A
{
A_fixed_B(A const& src) : A(src) {}
A const& asA() const { return *this; } // Base Conversion is OK inside class.
using A::GetPropertyA;
using A::GetPropertyB;
using A::SetPropertyA;
};
You can now create a std::vector<A_fixed_B> which behaves as you'd probably expect.
The easier thing to do would be to wrap std::vector<A> and return some form of proxy object.
class WrappedVectorA : private std::vector<A> {
struct MyProxy {
MyProxy(A& ref) { ptr = &ref; }
A* ptr;
PropertyA GetPropertyA() const { return ptr->GetPropertyA(); }
PropertyB GetPropertyB() const { return ptr->GetPropertyB(); }
SetPropertyA( const PropertyA& b ) { return ptr->SetPropertyA(b); }
operator=(const A& a) { *ptr = a; }
operator const A&() const { return *ptr; }
operator A() { return *ptr; }
};
public:
MyProxy operator[](int index) {
return std::vector<A>::operator[](index);
}
const MyProxy operator[](int index) const {
return const_cast<A&>(std::vector<A>::operator[](index));
}
};
It's really kind of ugly, but it'll work. I guess you'd also need to wrap the iterators and at(). However, A itself doesn't need to know anything about this, and normal std::vector<A> are completely untouched.
I'll go with that :
class IA {
public:
virtual ~IA() {}
virtual PropertyA& GetPropertyA() = 0;
virtual void SetPropertyA(const PropertyA& a) = 0;
};
class A : public IA
{
public:
A();
A( const PropertyB& b );
PropertyA& GetPropertyA();
PropertyB GetPropertyB();
void SetPropertyA( const PropertyA& b );
void SetPropertyB( const PropertyB& b );
};
template< PropertyB value >
class fixedVector {
private:
std::vector<A> _tab;
public:
void pushback() {_tab.pushback(A(value)); }
IA& get(unsigned int i) { return _tab[i]; }
void popback() { _tab.pop_back(); }
};
If your A object are instanciate by a proxy, you could use a directly a std::vector< std::autoptr<AI> >;
Use a flyweight for the storage of PropertyB and throw an exception in SetPropertyB, if the count of elements in the flyweight is greater than 1 after the assignment.
Different PropertyBs will not be allowed no matter which container you store the As in.
#include <boost/flyweight.hpp>
class A
{
public:
A();
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
SetPropertyB( const PropertyB& b );
private:
PropertyA a;
boost::flyweights::flyweight<PropertyB> b;
};
A::SetPropertyB(const PropertyB& item)
{
b = item;
if(b.size() > 1) // you may have to implement flyweight::size() yourself
// should be able to do this based on core::factory().size();
throw InsaneArrayExcpetion();
}
Haven't actually tested if this code compiles, but it gives you the idea.
I would go with "Wrapping std::vector< A >..." approach. In that way user of the class will not be able to modify the objects in the vector where as if they want to call SetPropertyB they can create a copy of the object returned from this wrapper and use that method.
Use a policy base class to determine which fields can be set - this will generate a compile time error if you try to set the wrong property. The downside of course is that A is no longer simply A, but is typed on the policy.
Code:
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
class AllPolicy
{
public:
void setA(int a) { _setA(a); }
void setB(int b) { _setB(b); }
private:
virtual void _setA(int a) = 0;
virtual void _setB(int b) = 0;
};
class APolicy
{
public:
void setA(int a) { _setA(a); }
typedef void setB;
private:
virtual void _setA(int a) = 0;
};
class BPolicy
{
public:
void setB(int b) { _setB(b); }
typedef void setA;
private:
virtual void _setB(int b) = 0;
};
template <typename Policy>
class A : public Policy
{
public:
A(int a = 0, int b = 0) : _a(a), _b(b)
{
}
A(A const& v) : _a(v._a), _b(v._b)
{
}
~A() {}
A& operator=(A const& v)
{
_a = v._a;
_b = v._b;
return *this;
}
int getA() const { return _a; }
int getB() const { return _b; }
using Policy::setA;
using Policy::setB;
private:
virtual void _setA(int a) { _a = a; }
virtual void _setB(int b) { _b = b; }
private:
int _a;
int _b;
};
int main(void)
{
std::vector<A<AllPolicy> > all_v(1, A<AllPolicy>(2, 3));
all_v[0].setA(1);
all_v[0].setB(2);
std::vector<A<APolicy> > a_v(1, A<APolicy>(2));
a_v[0].setA(1);
a_v[0].setB(2);
std::vector<A<BPolicy> > b_v(1, A<BPolicy>(1, 3));
b_v[0].setA(1);
b_v[0].setB(2);
}
Demo: http://www.ideone.com/mTJSb
So the idea is to use inheritance and the base class of A will expose what can be set. In the AllPolicy case, both methods are exposed, and in the other case one or other of the setters are exposed. A compiler error should result (as in the demo) if you try to use the opposite setter to the policy. Of course now A<APolicy> is not the same as A<BPolicy>, and if you wanted conversion, you'll have to provide conversion constructors etc.