Re: user-defined op= for type with reference member
"Leigh Johnston" <le...@i42.co.uk> wrote:
"Pete Becker" <p...@versatilecoding.com> wrote in message
news:2010061111295323604-pete@versatilecodingcom...
On 2010-06-11 11:21:09 -1000, Paul Bibbings said:
Since I have used the following in another post, can someone just
confirm (or otherwise) whether the following definition of a
user-defined op= for a type with a reference member is well defined?
class AType
{
public:
AType(int& i)
: i_(i)
{ }
// ...
AType& operator=(const AType& other)
{
if (this != &other)
{
this->~Atype();
new (this) AType(other);
}
return *this;
}
private:
int& i_;
};
According to my reading of the example given in [basic.life] 3.8/7 I
believe that it is, in this instance (since the constructor doesn't
throw, except on bad_alloc).
Yes, it's well-defined, but it's a really bad idea:
class BType : public AType
{
public:
BType& operator=(const BType& other)
{
return AType::operator==(other);
}
};
BType b1, b2;
b2 = b1; // nasty
In this particular example, there's almost certainly no nasty behavior.
But add a virtual function to AType (and make AType's destructor virtua=
l)
and override the function in BType.
AType *at = &b2;
at->virtual_function();
Now things are messy, because the code says that b2 has type BType, but
BType's constructor has not been called.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
It is well defined in the sense that it is defined to be undefined
behaviour. You cannot reseat references.
/Leigh
I'm not so sure whether the following could come interesting in this
case (nothing special for the most experienced ones, I suppose): it is
possible to store the reference as a pointer and create a "resettable
reference" in either of the following ways:
-------
#include <iostream>
using namespace std;
class IntByRef {
public:
explicit IntByRef(int& i) : ptr(&i) {};
operator int&() {
return *ptr;
}
int& operator=(int& i) {
ptr= &i;
return *ptr;
}
private:
int* ptr;
};
int main()
{
int local = 8;
IntByRef ibr(local);
cout << ibr << endl; // prints 8
local = 10;
cout << ibr << endl; // prints 10
int local2 = 42;
ibr = local2;
cout << ibr << endl; // prints 42
int& intref = ibr;
++ibr;
ibr *= 2;
ibr -= 8;
cout << intref << endl; // prints 78;
return 0;
}
-------
-------
#include <iostream>
using namespace std;
class SimplerIntByRef {
public:
SimplerIntByRef (int& i) : ptr(&i) {};
operator int&() {
return *ptr;
}
private:
int* ptr;
};
int main()
{
int local = 8;
SimplerIntByRef ibr(local);
cout << ibr << endl; // prints 8
local = 10;
cout << ibr << endl; // prints 10
int local2 = 42;
ibr = local2;
cout << ibr << endl; // prints 42
int& intref = ibr;
++ibr;
ibr *= 2;
ibr -= 8;
cout << intref << endl; // prints 78;
return 0;
}
-------
main() is practically identical for both cases, you can apply all
combined operator+equals to an IntByRef as well as all pre and post
increment/decrement, the only thing that you can't assign to it is a
constant or a temporary (that would be a plain rvalue) - by the means
of using operator= or by using the implicit ctor in the simpler case.
You can only (re)assign it to "point" to another (non-const) variable.
Modulo mistakes and misunderstandings as usual, I'm ready to have my
"view" fixed :-)
--
FSC
http://userscripts.org/scripts/show/59948