I have the following contrived example (coming from real code):
template <class T>
class Base {
public:
Base(int a):x(a) {}
Base(Base<T> * &other) { }
virtual ~Base() {}
private:
int x;
};
template <class T>
class Derived:public Base<T>{
public:
Derived(int x):Base<T>(x) {}
Derived(Derived<T>* &other): Base<T>(other) {}
};
int main() {
Derived<int> *x=new Derived<int>(1);
Derived<int> y(x);
}
When I try to compile this, I get:
1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27: instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error: initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’
1) Clearly gcc is being confused by the constructors. If I remove the reference
from the constructors, then the code compiles. So my assumption is that something goes wrong
with up-casting pointer references. Can someone tell me what is going on here?
2) A slightly unrelated question. If I were to do something horrendous like "delete other" in the constructor (bear with me),
what happens when someone passes me a pointer to something on the stack ?
E.g. Derived<int> x(2);
Derived<int> y(x);
where
Derived(Derived<T>*& other) { delete other;}
How can I make sure that pointer is legitimately pointing to something on the heap?
Base<T> is a base type of Derived<T>, but Base<T>* is not a base type of Derived<T>*. You can pass a derived pointer in place of a base pointer, but you can't pass a derived pointer reference in place of a base pointer reference.
The reason is that, suppose you could, and suppose the constructor of Base were to write some value into the reference:
Base(Base<T> * &other) {
Base<T> *thing = new Base<T>(12);
other = thing;
}
You've just written a pointer to something which is not a Derived<T>, into a pointer to Derived<T>. The compiler can't let this happen.
You cannot convert a reference to a pointer to Derived to a reference to a pointer to Base. (Templates don't contribute to the issue here, so removed from my example below.)
If you want to defer responsibility for a pointer, use a smart pointer type. Smart pointer types can represent the "responsibility to delete" that raw pointers cannot. Examples include std::auto_ptr and boost::shared_ptr, among many others.
Why you cannot upcast pointer references:
struct Base {};
struct Derived : Base {};
struct Subclass : Base {};
int main() {
Derived d;
Derived* p = &d;
Derived*& d_ptr = p;
Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is
Base b;
b_ptr = &b; // oops! d_ptr no longer points to a Derived!
Subclass s;
b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}
When you pass your 'other' parameter to the Base ctor, you're trying to do the same thing as b_ptr = d_ptr above.
You make sure that pointer points to something on the heap by writing that in your documentation and relying on the caller to abide by that. If whoever calls your constructor passes a stack pointer, all bets are off, and it's not your fault - you can try to catch the problem early, but no guarantees.
That's how the standard library works - often it'll catch obvious errors, but it's not required to, and it's up to the caller to make sure they're not doing anything stupid.
Your x variable is not a pointer, it should be if you want to assign a new Derived<int> to it.
As for deleting things on the stack, don't do it. There is no way to tell whether you have been passed the address of something on the stack or on the heap (indeed, the C++ standard doesn't even acknowledge the existence of a stack). The lesson here is that you shouldn't be deleting things that you don't own, especially if you have no way of telling where they came from.
Not sure why do you want reference to the pointer. Why not
Base(Base<T> * other) { }
and
Derived(Derived<T>* other): Base<T>(other) {}
That should work.
And, like other answered, I don't think you can legitimately know whether the pointer is pointing into heap.
Edit: why can't one do what you're trying to: consider example:
Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;
Where Derived1 and Derived2 are different classes derived from Base? Would you think it's legitimate? Now that x of type Derived1* points to Derived2?
Related
According to C++03 12.4/12 when a destructor is invoked explicitly
if the object is not of the destructor’s class type and not of a class derived from the destructor’s class type, the program has undefined behavior
So I have this code:
class Base {};
class Derived : public Base {};
char memory[100];
new(memory) Derived();
Base* ptr = (Base*)memory;
ptr->~Base();
Here the object is of type Derived and "the destructor's class type" is Base and so it looks like according to the Standard wording there're no grounds for UB.
So does the code above yield UB according to the Standard?
Correct, there's no undefined behavior.
By contrast there is potential UB in this case depending on the types involved:
Base *ptr = new Derived();
delete ptr;
The reason is that for some types an adjustment might have been applied by the implementation to get from Derived* to Base*. So without the pointer to the complete object there's no way to free the memory allocation correctly. A virtual destructor ensures that the Base sub-object provides enough information for the implementation to recover that (the virtual call mechanism must be able to recover the Derived* pointer in order to pass it as this).
But in your example the memory isn't freed and so there's no motivation to make it UB. Of course it's still a bad idea, since conceptually the Derived object is in a broken state. You have no legitimate way to call ~Derived, even. In your example though both types are trivially destructible, so there's no need to call the destructor of either.
It's not UB, since both classes have trivial destructors, and therefore calling the destructor has the same effect as not calling the destructor (and not calling the destructor is certainly not UB).
please correct me if i'm wrong, i think there isn't undefined behavior but still should be avoided in sence of humanity (or maintainablity). but, consider Derived is creating some kind of member, e.g. a shared pointer, (which is not untypical even for exceptions :). i tried this code on my machine and also on codepad:
class Base {
public:
boost::shared_ptr<int> x;
};
class Derived : public Base {
public:
boost::shared_ptr<int> y;
};
int main(int argc, char *argv[]) {
boost::shared_ptr<int> xx(new int(0xff));
boost::shared_ptr<int> yy(new int(0xaa));
int memory[100];
for(int i=0; i<100; i++)
memory[i] = 0;
Derived* foo = new(memory) Derived();
foo->x = xx;
foo->y = yy;
(*foo->y)--;
Base* ptr = (Base*)foo;
ptr->~Base();
Derived* bar = new(memory) Derived();
bar->x = xx;
bar->y = yy;
foo->~Derived();
return 0;
}
here is that the shared_ptr yy isn't released, and nobody could guarantee to never forget about Derived shouldn't provide any kind of stuff.
Okay, so let's say I have some random abstract base class Base and I have a class Foo which contains a pointer to this base class as a datamember. So
class Foo
{
public:
Foo(Base*);
private:
Base* ptr;
}
Now the reason I use a pointer to the base class is because I want to be able to choose which derived class my Foo object has a pointer to. Now the tricky part is, to me, the implementation of the constructor for Foo.
If I do it like this
Foo::Foo(Base* _ptr)
{
Foo::ptr = _ptr;
};
it would be possible for the user to adjust the object pointed to by Foo::ptr since _ptr will still exist after the constructor has finished. I cannot make the object pointed to by _ptr constant because Foo::ptr needs to update itself regularly. Now I was thinking about adding a line _ptr = NULL at the end of the constructor, but that could be dangerous as well, since the user could try to dereference _ptr.
The only way I can think of to make this work is to make a copy of the object pointed to by _ptr and initializing Foo::ptr to the address of that copy. But then the object pointed to by _ptr would need to have a member function Clone() or something similar because I can't call the copy constructor for an object of which I don't know the class at compile-time.
So is there any elegant way of doing this if there is no Clone()? Or is that really the only possibility?
Construct from a unique_ptr. That way your user has no access to the pointer after it has been used in the creation of a Foo object (unless he really wants to and uses get).
e.g.
#include <memory>
struct Bar {};
struct Foo {
Foo(std::unique_ptr<Bar>&& ptr) : ptr_(std::move(ptr)) {}
std::unique_ptr<Bar> ptr_;
};
int main()
{
std::unique_ptr<Bar> tt(new Bar());
Foo f(std::move(tt));
return 0;
}
An alternative is using smart pointers. That way, ownership is assigned to the smart pointer implementation.
class base {
int a;
protected:
template<class T>
class derived;
public:
base() {}
virtual ~base() {}
virtual void func() {}
static base* maker();
};
template <class T>
class base::derived
: public base
{
public:
derived() {}
virtual ~derived() {}
virtual void func() {
this->~derived(); //<--is this legal?
new (this) derived<int>(); //<--is this legal?
}
};
base* base::maker() {
return new derived<double>();
}
int main() {
base* p = base::maker(); //p is derivedA<double>
p->func(); //p is now derivedA<int>
delete p; //is the compiler allowed to call ~derived<double>()?
}
This is a Short, Self Contained, Correct (Compilable), Example of my code (which is basically reinventing any_iterator for my own growth).
The question reduces down to: is it undefined behavior to destroy this and reconstruct this with a different type virtually derived from the same base, when neither has any additional members over the shared base? Specifically, are compilers allowed to call keep track of the static type, or is that technically nonconforming?
[EDIT] Several people pointed out that compilers may call the incorrect destructor if derivedA is created on the stack. (1) I can't find anything in the standard that allows compilers to do so. (2) That was aside from what I intended by my question, so I have changed the code to show that derived cannot be placed on the stack. base can still be on the stack though.
I think that's clearly not OK.
As a preface, and object's lifetime can indeed be ended by calling the destructor, but you're only allowed (and required) to construct a new object of the same type in its place:
{
Foo x;
x.~Foo();
::new (&x) Foo;
} // x.~Foo() must be a valid call here!
Remember that at scope's end the destructor will be invoked!
But in your case you're constructing an entirely different object:
::new (&x) Bar; // Bar = DerivedA<int>
Clearly if sizeof(Bar) exceeds sizeof(Foo) this cannot be OK.
(Perhaps if you can make additional guarantees on the object sizes, as well as on the alignment guarantees, we can think about this further.)
Update: Even if you're thinking, OK, so those types are derived from the same base, so invoking the destructor brings virtual happiness, I'm still pretty sure that that's a violation. In this static setting, the compiler may well resolve the virtual call statically, so you're breaking the compiler's assumptions if you change the dynamic type of the thing pointed to by &x.
Update 2: Another thought on the same matter: The static type of *&x is known, and I think you have to respect that. In other words, the compiler has no reason to factor in the possibility that the static type of a local variable changes.
I'm pretty sure that is not valid code for several reasons:
If the inserted type isn't the same size bad things will happen (I'm not quite sure but I think the standard doesn't make to much promises about the size of a type, so from the theoretical vantage point it might be hard to prove that they have the same size (through in praxis they most likely will))
if the type of the variable is statically known (probably due to it beeing constructed on the stack, but it in theory it could do the same thing if it can see the allocaiton and prove that the pointer couldn't have been modified) the compiler can feel free to statically reolve virtual method calls (e.g. a destructor) and use them which would obviously break the code
Even if the type of the variable is not statically known I'm quite sure the compiler can assume that it's type won't change during it's lifetime (The pointer can't change inside the function so it should be able to assume the pointed to type doesn't either). Therefore while it can't statically resolve methods it could possibly reuse the vmt pointer from previous invocations of virtual methods (e.g. the one changing the type)
Edit: now that I think about it doesn't this break strict aliasing rules, since after the placement new this points to a non compatible type? granted it isn't explicietly accessed in the function again, but I don't think it can be guranteed that there won't be accesses inserted by the compiler (highly unlikely though). Anyways this would mean that the compiler can assume that this kind of action won't happen.
Edit: When looking at the new C++ Standard I found that [basic.life] (§3.8.5) gives what is basically the same thing as an example of undefined behaviour (it doesn't actually destroy the object, but I don't see how that could make matters better):
#include<cstdlib>
structB{
virtual void f();
void mutate();
virtual ~B();
};
struct D1:B { void f(); };
struct D2:B { void f(); };
void B::mutate(){
new(this)D2; //reuses storage—ends the lifetime of *this
f(); //undefined behavior
...=this; //OK, this points to valid memory
}
void g(){
void* p = std::malloc(sizeof(D1) + sizeof(D2));
B* pb = new(p)D1;
pb->mutate();
&pb; //OK: pb points to valid memory
void* q = pb; //OK: pb points to valid memory
pb->f(); //undefined behavior, lifetime of *pb hasended
}
This should prove that this is not allowed.
If I understand slicing correctly I don't think this could happen with pointers or smart pointers. For example, if you had:
class A
{
int something;
};
class B : public A
{
int stuff;
int morestuff;
};
int main()
{
std::shared_ptr<B> b(new B());
std::shared_ptr<A> a;
a = b;
}
My understanding is that the block of memory allocated to the object pointed to by "b" is still the same and doesn't change when assigned to the smart pointer "a".
Please confirm or reject my understanding, or let me know of any pitfalls associated with this.
A smart pointer is still a pointer, so such an assignment won't cause slicing. Slicing happens only when dealing with values, not pointers. Note, however, templates don't know about the relationships between the items the point at, so even though B derives from A, shared_pointer<B> doesn't derived from shared_pointer<A>, so an assignment doesn't (automatically) get an automatic up-cast like it would with native pointers.
Edit: elaborating on final point.
Slicing happens with values, not pointers, so (given your definitions of A and B), something like:
A ax = b;
would work, but would "slice" the B object to become an A object. If, however, you have some sort of template that holds an instance of the item:
template <class T>
class holder {
T t_;
public:
holder &operator=(T const &t) {
t_ = t;
return *this;
}
holder &operator=(holder const &t) { t_ = t; return *this; }
};
Now, if we try to assign one value to another, like would cause slicing:
holder<A> ha;
holder<B> hb;
A a;
B b;
ha = a;
hb = b;
ha = hb;
we will NOT get slicing. Instead, the compiler will simply give us an error, telling us that holder<A> and holder<B> are not related types, so the assignment can't happen -- without adding an explicit cast, it simply won't compile.
You're correct, but they're not the same: you can't evaluate a->stuff.
#include "iostream"
class A {
private:
int a;
public :
A(): a(-1) {}
int getA() {
return a;
}
};
class A;
class B : public A {
private:
int b;
public:
B() : b(-1) {}
int getB() {
return b;
}
};
int main() {
std::auto_ptr<A> a = new A();
std::auto_ptr<B> b = dynamic_cast<std::auto_ptr<B> > (a);
return 0;
}
ERROR: cannot dynamic_cast `(&a)->std::auto_ptr<_Tp>::get() const
Well, std::auto_ptr<B> is not derived from std::auto_ptr<A>. But B is derived from A. The auto_ptr does not know about that (it's not that clever). Looks like you want to use a shared ownership pointer. boost::shared_ptr is ideal, it also provides a dynamic_pointer_cast:
boost::shared_ptr<A> a = new A();
boost::shared_ptr<B> b = dynamic_pointer_cast<B> (a);
For auto_ptr, such a thing can't really work. Because ownership will move to b. But if the cast fails, b can't get ownership. It's not clear what to do then to me. You would probably have to say if the cast fails, a will keep having the ownership - which sounds like it will cause serious trouble. Best start using shared_ptr. Both a and b then would point to the same object - but B as a shared_ptr<B> and a as a shared_ptr<A>
dynamic cast doesn't work that way. A : public B does not imply auto_ptr<A> : public auto_ptr<B>. This is why boost's shared_ptr provides shared_dynamic_cast. You could write an auto_ptr dynamic cast though:
template<typename R, typename T>
std::auto_ptr<R> auto_ptr_dynamic_cast(std::auto_ptr<T>& in) {
auto_ptr<R> rv;
R* p;
if( p = dynamic_cast<R*>( in.get() ) ) {
in.release();
rv = p;
}
return rv;
}
Just be aware of what happens here. Since auto_ptrs have ownership semantics, a successful downcast means the original more generally typed, auto_ptr no longer has ownership.
The reason is that auto_ptr is not actually a pointer. It's a smart pointer which is a pointer wrapper but not actually a pointer. The type that is passed as a template style argument to dynamic_cast must be a true pointer (or reference) type.
http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx
You're trying to cast a A* (returned by a.get()) to std::auto_ptr<B>, and since the second is not even a pointer type this fails. Probably you just want to cast it to B*:
std::auto_ptr<A> a(new A());
std::auto_ptr<B> b(dynamic_cast<B*>(a.get()));
This will still not compile, because A and B aren't polymorphic types. A needs to have a virtual function in order to make the types polymorphic. This will compile, but the cast will just throw std::bad_cast, since it isn't really a B*.
And even if it were a B*, it will fail in horrendous ways if you try to use it. Both std::auto_ptrs a and b will assume they own the object and free it later on, resulting in all kinds of memory corruption. You probably want to use a.release() after the cast was successful.
I think c++ stores RTTI (run time type information) in the vtable. Hence to use dynamic_cast<> with an instance object, the object needs have 'vtable'. C++ creates vtable only when at least one function is declared 'virtual' in the class.
The class A and Class B there are no virtual functions. This could be reason for the dynamic_cast failure. Try declaring a virtual destructor in base class.