"Leigh Johnston" <leigh@i42.co.uk> wrote...
On 03/03/2011 07:37, Liviu wrote:
[...]
void A::f(int n)
{
cout<< "A::f, object "<< count - B::count<< ", this = "<<
(const void *)this<< endl;
if(n)
{
this->~A();
/*
note: right here 'this' points to an unitialized object,
which is legal for essentially the same reasons
why 'delete this' is allowed in member functions
*/
(n % 3) ? new(this) A : new(this) B;
f(n - 1); // <<=== 3.8/5
}
}
[...]
That looks like undefined behaviour to me; see 3.8/5.
I guess you refer to the "pointer is used as the operand of a
dynamic_cast" part, which is implicitly done in the f(n-1) call above.
That is a technical violation, indeed, though inconsequential in the
simple example at hand.
That said, below is a modified version which covers the general case
where B can have extra data members and/or be derived through
multiple inheritance. Note that the two asserts never fire, which
confirms that the example satisfies the original requirement that the
pointer doesn't change.
Liviu
P.S. The following is meant to show that a recursive member function
call may land on different objects, and even different types of
objects.
Disclaimer: just because it's possible doesn't mean it's advisable ;-)
That said, the code compiles cleanly under Comeau online in strict
mode.
A test run on my machine outputs:
A::f, object 1, this = 0012FF54
A::f, object 2, this = 0012FF54
B::f, object 1, this = 0012FF54
B::f, object 2, this = 0012FF54
B::f, object 3, this = 0012FF54
A::f, object 3, this = 0012FF54
A::f, object 4, this = 0012FF54
A::f, object 5, this = 0012FF54
B::f, object 4, this = 0012FF54
B::f, object 5, this = 0012FF54
B::f, object 6, this = 0012FF54
//--------------------------------
#include <cstdlib>
#include <cassert>
#include <algorithm>
using std::max;
#include <iostream>
using std::cout;
using std::endl;
struct A
{
static int count, alive;
A() { count++; alive++; }
~A() { alive--; }
virtual void f(int n);
};
struct B : public A
{
static int count, alive;
B() { count++; alive++; }
~B() { alive--; }
virtual void f(int n);
};
int A::count, A::alive, B::count, B::alive;
void A::f(int n)
{
cout << "A::f, object " << count - B::count << ", this = " << (const
void *)this << endl;
if(n)
{
this->~A();
/*
note: right here 'this' points to an unitialized object,
which is legal for essentially the same reasons
why 'delete this' is allowed in member functions
*/
A *that = (n % 3) ? new(this) A : new(this) B;
assert(this == that);
that->f(n - 1);
}
}
void B::f(int n)
{
cout << "B::f, object " << count<< ", this = " << (const void *)this
<< endl;
if(n)
{
this->~B();
A *that = (n % 3) ? new(this) B : new(this) A;
assert(this == that);
that->f(n - 1);
}
}
int main()
{
void *p = malloc(max(sizeof(A), sizeof(B)));
A *a = new(p) A;
a->f(10);
a->~A();
free(p);
}
//--------------------------------
Are you trying to prove that "belongs to " is bad terminology . Are you