Is there any significant difference in performance, memory, etc, between:
#1: moving a pointer to a temporary pointer, moving it back, then deleting the temporary pointer
#2: copying a pointer to a temporary pointer, then deleting the temporary pointer
I have the following code, two pointer of objects a Base and a Derived (which is derived from Base) are allowed to be stored inside a vector of pointers of Base objects, when reading the vector I need to check whether I need to dynamic_pointer_cast the pointer so data doesn't get sliced off.
#include "Base.h"
#include "Derived.h"
class Base
{
public:
Base() {};
~Base() {};
};
class Derived: public Base
{
public:
Derived() {};
~Derived() {};
};
int main()
{
std::vector<std::shared_ptr<Base>> vectorOfBaseObjects;
std::shared_ptr<Base> base = std::make_shared<Base>();
std::shared_ptr<Derived> derived = std::make_shared<Derived>();
vectorOfBaseObjects.push_back(base);
vectorOfBaseObjects.push_back(derived);
for (auto &it : vectorOfBaseObjects) {
// #1: Move pointer to a temporary location and move it back when done
if (std::shared_ptr<Derived> tmp_ptr = std::move(std::dynamic_pointer_cast<Derived>(it))) {
// Do something with the derived object
it = std::move(tmp_ptr);
}
// #2: Create a new temporary pointer
if (std::shared_ptr<Derived> tmp_ptr = std::dynamic_pointer_cast<Derived>(it)) {
// Do something with the derived object
}
}
}
Both statements work just fine, the only issues I could make of might be
#1: missing pointer locations in multi threaded appications in very rare cases, which could become a problem.
#2: an additional location assigned in the memory, which shoulnd't be an issue at all.
The two cases are pretty much equivalent, since std::dynamic_pointer_cast() returns a new shared pointer. it is not moved from in this expression:
std::move(std::dynamic_pointer_cast<Derived>(it))
The result of the cast is already an xvalue, so that's exactly the same as
std::dynamic_pointer_cast<Derived>(it)
The only difference is the copy of the pointer back to it. If you've not changed what it points to, then that's a wasted statement.
If you're worried about the speed of creating new shared_ptrs then tmp_ptr probably doesn't even need to be a shared_ptr. Using a raw pointer would look like this:
Derived* tmp_ptr = dynamic_cast<Derived*>(it.get());
Related
I thought i knew pointers but then as i study run time polymorphism/dynamic binding, i've seen a very different use for pointers. Here are my 3 questions, they're all regarding the single line code below:
#include <iostream>
class Base {
public:
virtual void fun (int x) { std::cout << "base" << std::endl; }
};
class Derived : public Base {
public:
void fun (int x) { std::cout << "base" << std::endl; }
};
int main() {
//--------------------------------------
//1. Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
//2. What's the point of putting this into heap?
//3. I thought pointers could only hold memory address of the same datatype/class
Base* obj = new Derived();
//--------------------------------------
obj->fun(5);
return 0;
}
Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
The expression here is not Derived() (which would indeed construct a temporary object), but new Derived(), which is new's specific syntax to allocate and construct an object with dynamic lifetime and return a pointer to it. Note that the corresponding delete to end the object's lifetime is missing, but see the next point.
What's the point of putting this into heap?
None. In particular, the lifetime of an object does not affect the use of pointers with it, nor are pointers required for polymorphism (references work just as well). In any case, dynamic allocation should be done with smart pointers, not naked news.
I thought pointers could only hold memory address of the same datatype/class
That's still true: obj is pointing at the Base subobject of the Derived object. C++ provides an implicit pointer-adjusting conversion from Derived * to Base * (and Derived & to Base & as well) to facilitate the use of polymorphism.
Pointer can only hold memory address, 'Derived()' is calling the default constructor it is not a memory address
A new expression does multiple things. First, it allocates enough memory for the type of object. Then, it calls the constructor for that type at the allocated memory. Then, it returns a pointer to the newly created object. Pointers point to objects. new returns a pointer to an object. So there is no problem here, obj will now point to the newly created Derived object.
What's the point of putting this into heap?
It isn't strictly necessary to dynamically create an object here. You could just as easily have the following and illustrate polymorphism :
Derived foo;
Base* obj = &foo;
Maybe the author of this example didn't think of that, or maybe they wanted to illustrate the mechanics of new at the same time. You'd have to ask them.
I thought pointers could only hold memory address of the same datatype/class
It is true that obj is a Base* so it can only point to a Base type object. But a Derived object is also a Base object, so obj can easily point to a Derived object. That is what public inheritance achieves. The : public Base part of class Derived : public Base means Derived is also a Base.
Pointers can point to anything with a memory address.
A pointer to an instance of a derived class can be handled as if it were a pointer to the base class, even if the base class itself is abstract (unable to be instantiated itself). That's how polymorphism works in C++.
Why put a pointer to an object on the stack and the object itself into the heap? Many reasons, some of them good and others not so good.
class base
{
virtual ~base();
};
class der1 :public base
{
int i;
}
class der2 :public base //I used double that der2 is bigger than der1
{
double d;
}
int main()
{
base* ptr = new der2;
ptr->~base(); //Destructor call just for the
//case that the der2 had a pointer member
der1* ptr2 = static_cast<der1*>(ptr);
*ptr2 = der1();
delete ptr;
return 0;
}
What would happen if you would execute the code shown above?
Would this produce a memory leak and if yes why?
Is there a possibility to use the taken memory for different types without releasing it first? (Please no answers like why should you need this, it's just interest)
Edit:
The ~base() does nothing because this is an example.
It's undefined behaviour since you assign to, and delete an object after its lifetime has ended, which is forbidden by C++11, [basic.life]/5:
after the lifetime of an object has ended and before the storage which the object occupied is
reused or released, any pointer that refers to the storage location where the object will be or was located
may be used but only in limited ways. The program has undefined behavior if:
the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a
delete-expression
the pointer is used to [...] call a non-static member function of the object
(plus a few other restrictions.) You try to do both of these things.
If you were to fix this, by creating a new object in the old memory rather than assigning to it as if there were already an object there:
der1* ptr2 = new (ptr) der1;
then it's still undefined behaviour, as stated in C++11, [basic.life]/7
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or
released, a new object is created at the storage location which the original object occupied, a pointer that
pointed to the original object [...] can
be used to manipulate the new object, if [...] the new object is of the same type as the original object
(plus a few other conditions). You use an pointer to the old object to manipulate (specifically, to delete) the new object of a different type.
I came across a weird situation today while coding and I'm hoping someone could shed some light onto why this is happening.
I have a list of pointers to some base class:
std::list<BaseClass*> m_list;
Then I get one of the BaseClass pointers from this list
BaseClass* pBase = m_list.front();
Then I turn this base class into one of its child classes. (This is where I think the weirdness comes into play)
pBase = new ChildClass(*pBase);
The ChildClass uses the BaseClasses copy constructor to copy over all of BaseClasses fields.
Now with this ChildClass I call one of BaseClasses methods to set a field in BaseClass.
pBase->SetSomeIntMember(10);
Now if I check this int value it is 10 as expected, but it appears to only be changing it locally because if I get this same ChildClass from the list again and check it's int member it will be unchanged.
Hopefully this wasn't too tricky to follow. What makes this happen? In any situation where there is no polymorphism involved it would obviously not only be a local change as we have a pointer to the class instance. I'm guessing that I'm stomping on the pointer when I create a new ChildClass, but it definitely makes the BaseClass from the list become a ChildClass because the virtual methods still work.
pBase = new ChildClass(pBase);
This doesn't "make the BaseClass from the list become a ChildClass". It creates a new instance of ChildClass. Only changes to pBase done in ChildClass's constructor could affect what pbase pointed to before. (You cannot make one class "become an instance of a child class".)
That line of code does not change m_list at all. m_list still contains a pointer to the original BaseClass object.
You copy the value of the pointer, not a reference to the pointer.
That is,
BaseClass* pBase = m_list.front();
pBase = new ChildClass(*pBase);
is not the same as
Baseclass*& pBase_r = m_list.front();
pBase_r = new ChildClass(*pBase_r);
Remember, if you want to update the original value, you need to use references or pointers.
Note
The second example contains a memory leak since the original value of pBase is discarded before delete. To avoid such surprises, use smart pointers, e.g. std::shared_ptr<T> (C++11) or boost::shared_ptr<T> in place of T*.
Do not use std::auto_ptr<T> because its semantics are not compatible with STL containers.
So your list class should be std::list<std::shared_ptr<BaseClass>>. Another advantage here is that you can use instances of the smart pointer instead of references without messing up the internal reference count.
at first look you were just assigning the newly allocated pointer by value to pBase. The list element is actually the pointer address which got copied by value to pBase. The list element actually didn't get changed
try this instead
BaseClass** pBase = &(m_list.front());
BaseClass* pOld = *pBase;
*pBase = new ChildClass(**pBase); // you have a leak here of *pBase BTW
deleteOrCleanup(pOld); // cleanup or delete the old pBase pointer
//do what you were doing
As others have pointed out, your problem is that you're simply modifying the local copy of a pointer, and not what it's actually pointing to.
Instead of sticking raw pointers into containers and having to manually delete them (or leaking memory) when you try to replace container elements, use smart pointers.
#include <memory>
#include <list>
#include <iostream>
struct base
{
base( int a )
: x(a)
{}
int x;
};
struct derived : base
{
derived( int a )
: base(a)
{}
};
int main()
{
std::list<std::unique_ptr<base>> mylist;
mylist.push_back( std::unique_ptr<base>( new derived(10) ) );
auto pbase = mylist.front().get(); // get raw pointer to first element
std::cout << pbase->x << std::endl;
pbase = new derived( 10 * pbase->x ); // create a new derived object
mylist.front().reset( pbase ); // replace the first element, previous
// element is deleted automatically
pbase = mylist.front().get();
std::cout << pbase->x << std::endl;
// all allocated objects will be automatically deleted
// when mylist goes out of scope
}
Output:
10
100
If my class has a pointer of some sort that can be set by the class clients, how should I deal with deletion?
Example:
class A {
};
class B {
public:
void setA(A* a) {
this->a = a;
}
private:
A* a;
};
How should be the destructor of the class B? Should it delete a? As I see, there are two way a user can set this pointer:
... // Assume B object b being created elsewhere
A aObj;
A* aPtr = new A();
b.setA(&aObj); // It is not OK to use delete, and class member will
// point to invalid memory location once aObj goes out
// of scope
b.setA(aPtr); // Using new will make the pointer available even after
// this block of code
...
So what is the right way of deleting b? Should I always perform a new in my set method?
How should be the destructor of the class B? Should it delete a?
You, the author of the class, decides of its semantics. Don't think in terms of pointers, references, and deletes. Think in terms of design: what's the relation between A and B? What does B needs a A for?
Two common types of relation are delegation and composition. Delegation would mean that client code uses the setA member to have the instance aware of some other B instance that it may use for further uses. Composition would mean that the setA member is used to initialize an internal part of the instance.
One possible implementation of delegation is using a member pointer. I'd recommend passing a reference to setA to assign to that pointer; it sidesteps the issue of checking for 0 and makes it obvious to client code that there is no ownership issue to deal with. This is compatible with polymorphic types.
One possible implementation of composition is using a A member, and passing by reference to const or by value to assign to it. Another is to use a smart pointer, especially if A is meant to be used polymorphically. Passing by smart pointer is the simplest thing to do -- but you'll have to check for 0 and/or document the cast.
No matter what you decide to use (which doesn't have to be in this list anyway), use code as a tool to achieve your purpose or design. Don't let code dictate your thoughts.
In all my example implementations you don't have to do anything special in the destructor.
You should really really not have such a class in the first place. Instead, use a resource managing container like shared_ptr or unique_ptr to hold the pointer to a dynamically allocated object.
As you can easily see, there's no way you'll manage to keep track of who's responsible for what if you randomly allocate dynamic objects all over the place. What about copying and assignment of your class? What about exceptions in the constructor? Don't do it.
I think there would normally be be 3 scenarios, see code below:
//class B doesn't own a
class B {
public:
void setA(A& a) {
m_a = a;
}
private:
A& m_a; //Only a reference , so need to worry about delete
};
//class B owns A
class B {
public:
void setA(std::auto_ptr<A>& a) {
m_a.reset(a.release());
}
private:
boost::scoped_ptr<A> m_a; //m_a got deleted when instance of B lifetime end
};
//class B shared A with someone else
class B {
public:
void setA(boost::shared_ptr<A>& a) {
m_a = a;
}
private:
boost::shared_ptr<A> m_a; //m_a got deleted when no one need this pointer anymore(reference counting reduced to 0)
};
You have a design decision to make. Who should own the object?
The B object owns the A object, and setA passes ownership to B. B's destructor should delete the A.
Some outer code owns the A object. B will not delete it, but will depend on that outer code to destroy it at the proper time.
A smart pointer tracks the references to the A object and deletes it automatically when all references are destroyed.
The third option with the smart pointer is the simplest and most reliable, but all 3 choices can be made to work. The trick is to pick one and be deliberate about it.
During your design analysis you will have to answer the following questions:
Does object A depends on the lifetime of object B, if yes then use "composition" in which case object B will create A and is responsible for deleting it before object B itself is destroyed.
If object A is independent of the lifetime of object B then use "aggregation". You supply object A to B via B's constructor or a set method. Object B does not have to worry about destroying object A but you will have to be certain that during the lifetime of B that A is in a valid state.
If A depends on object B's lifetime but you need to create A before B, then do "dependency injection". It's like aggregation in that you can pass A to B in the constructor or set method, but A is exclusively used by B in this case and no other object is using A. B deletes A before its own destruction.
From the looks of this, you are trying to create a reference to your A object within your B class.
To clean up B properly, you would have to check if A is null first. Something like...
~B()
{
if (A)
{
delete A;
A = 0;
}
}
Keep in mind this also deletes the A object outside of the class, because they're referencing the same memory. So in a case like this, you could VERY easily reference a pointer to invalid memory if you deleted the A object.
I would not use this with a local variable either btw, as you'll lose the address of it when it goes out of scope. However, a local pointer on the other hand..well, then you won't have to worry about referencing invalid memory once you've left the scope of where A was created.
#include <iostream>
using std::cout;
using std::endl;
class Base
{
public :
void f();
void g();
int mBaseData1;
};
class Derived : public Base
{
public :
int mDerivedData1;
};
void main()
{
Base* base = new Base();
Derived* derived = (Derived*)(base); // DownCast
derived->mDerivedData1 = 6;
cout<< derived->mDerivedData1<<endl; // Result = 6;
}
in this code new base() allocate memory in heap
and Derived* derived = (Derived*)(base) cast base to derived
how we can use mDerivedData1? i cant find where we allocate memory for mDerivedData1 or when we call constructor of Derived for allocate mDerivedData1 ?
The reason you can't find where memory for mDerivedData1 was allocated is because no memory was allocated. You have performed an invalid type-cast. The thing stored in base is a pointer to a Base instance. Using a type-cast to tell the compiler that it's actually a pointer to a Derived instance doesn't make it so (but the compiler will believe you anyway because you're the one in charge). The object is still just a Base. If you want a Derived, then you'll need to instantiate a Derived. You can use dynamic_cast to convert the Base pointer into a Derived pointer.
Base* base = new Derived;
Derived* derived = dynamic_cast<Derived*>(base);
derived->mDerivedData1 = 6;
It will work correctly if you change:
Base* base = new Base();
to:
Base* base = new Derived();
but in general you should never downcast unless you are really sure you know what you are doing, and even then it's usually a sign of a very bad design.
You are really overwritting some part of the heap that is not part of the original base object. This could overwrite another object on the heap, or other unexplained happenings could occur.
C++ lets you do what you tell it to do for the most part. You are shooting yourself in the foot. :)
Your program exhibits undefined behavior. You cannot access mDerivedData1 because you don't actually have an instance of Derived.
You can cast an instance of a child class to a base class, but you cannot (well... should not) cast an instance of a base class into a child class.
Edit:
If you are confused about how casting works:
An object never actually changes during a cast -- in truth an object is really just a contiguous block of memory. When an object is cast, the only thing that changes is how the program sees and works with the object.
That's why casting an instance of a base object to a child object results in undefined behavior; the runtime interprets the base object as a child object and uses the pointer for the object as a starting point for referencing data of the object. If a field that is defined on the child class is used on a base object cast as the child object, the program will reference memory that is not part of the instance. If this referenced memory happens to be unused by the rest of the program, things might seem just fine (for a little while), but if the memory is used by another object, strange things could happen in your program -- the other object might have a value changed that it shouldn't have, or worse. And this is just when dealing with heap allocated objects; try this with a pointer to a stack allocated object and you could totally derail your entire program -- assuming you don't segfault.
So in general, if B derives from A:
You can cast an instance of B to A
You can cast an instance of B that is already cast as an A back to B, but this may indicate sloppy architecture of your program.
You cannot (should not) cast an instance of A to B, as this will result in undefined behavior.