So I have a C++ function to which I pass a pointer to a base class, like:
void DoStuffAndAssignPtr(MyBase* ptr)
{
MyBase* p;
//do stuff
if (stuff was awesome) p = new MyAwesome();
else p = new MyBase();
//vftable of p before the return is MyAwesome
(*ptr) = (*p);
}
Now we need to invoke some virtual method that 'MyAwesome' and 'MyBase' implement differently. However, when checking the return value, as below:
void mainly()
{
MyBase* passMe = new MyBase();
DoStuffAndAssignPtr(passMe);
//now passMe is always being returned with MyBase's vftable
}
We can see that 'passMe' is always a 'MyBase' (as far as the vftable shows while debugging in VS). Can anyone provide any guidance as to why this is happening, and how I can ensure that 'passMe' will invoke 'MyAwesome' implementations of virtual methods?
The problem is with the use of (*ptr)=(*p). You should use ptr=p.
Only pointer and reference have polymorphism. When you use dereference (the star *), you lose this property, and only the base part is copied from p to ptr. This is because ptr only have space for that part of information.
You have object slicing issue, below statement slices MyAwesome object to MyBase:
(*ptr) = (*p)
You only pass MyBase* to DoStuffAndAssignPtr and tried to allocate a new pointer which will only overwrite the copy of function parameter. You need to pass the reference of the pointer instead.
void DoStuffAndAssignPtr(MyBase*& ptr);
^^^
Also as passMe is allocated by new outside DoStuffAndAssignPtr already, you created another membory for ptr inside DoStuffAndAssignPtr which will cause memory leak.
A better solution is:
MyBase* MakeAClass()
{
if (stuff was awesome)
{
return new MyAwesome();
}
return new MyBase();
}
int main()
{
MyBase* passMe = MakeBase()
}
Related
I want to allocate an object of type custom_type_t (operator= is not available for this custom_type_t and I'm unable to modify that part of the codebase) depending on whether a condition is met and, if it's not met, that object should not be created at all.
I was initially thinking I could do:
// create the object even if it's not needed
custom_type_t object; // just use their default constructor which hopefully isn't expensive
if (condition_met) {
object = custom_type_t(constructor arguments);
}
However, this isn't possible because there's no operator=.
I'm wondering if there's a way in which I can do something like the following:
int* custom_type_t ptr;
if (condition_met) {
custom_type_t object = custom_type_t(constructor arguments);
ptr = &custom_type_t;
} // but object may go out of scope here, so ptr may end up pointing to garbage
// ptr will be used later on if condition_met == true
But I need to have object actually remain valid so ptr doesn't point to garbage?
Your problems/confusion seem to lie in separating the idea of creating an object from that of explicitly declaring that object. You can quite easily (conditionally) create your object, and subsequently use it, by just declaring a pointer to it.
Using a simple 'raw' pointer, something like this (for the sake of the example, I have assumed that two int values are required for the constructor arguments):
void function()
{
custom_type_t* pObject = nullptr;
if (condition_met) {
pObject = new custom_type_t(42, -9);
}
// ...
delete pObject; // If still nullptr, no problem - does nothing.
}
Or, better, using a smart pointer:
void function()
{
std::unique_ptr<custom_type_t> pObject;
if (condition_met) {
pObject = std::make_unique<custom_type_t>(42, -9);
}
//...
// "pObject" is automagically freed when this function returns.
}
In either of the above cases, you can use *pObject in expressions where you would otherwise use object, and you can use pObject->memberFunc() instead of object.memberFunc().
I have a function that effectively does this
void foo(Class** c)
{
// memory checks and stuff
(*c) = new Class();
// more stuff
}
I cannot change this function. To call this function I have to do something like this.
Class* c = nullptr;
foo(&c);
if (c)
{
// stuff
}
delete c;
I would very much prefer to use a std::unique_ptr rather than the raw pointer. However, I don't know how to get the address of the internal pointer. The listing below does not compile, obviously, because I'm trying to take the address of an rvalue.
std::unique_ptr<Class> c = nullptr;
foo(&(c.get()));
if (c)
{
// stuff
}
I realize I could make the raw pointer as well as the unique pointer, call the function, then give the raw pointer to the unique pointer, but I would prefer to not. Is there a way to do what I want to do?
Create a wrapper around foo:
std::unique_ptr<Class> foo()
{
Class* c = nullptr;
foo(&c);
return std::unique_ptr<Class>(c);
}
Your hands are tied by the API of the function.
The best solution I personally see is to do what you said you'd rather not: create the unique_ptr after calling the function.
If you call this function a lot or if you have many functions like it I would create a wrapper function that creates locally the raw pointer and returns unique_ptr.
I have run into a strange problem. When i try to write a function that returns a pointer to a subclass which i swap for a different instance of that subclass i get the "error C2106: '=' : left operand must be l-value" error.
Tthe problems is at the one->getMe() = two; line :
class subClass{};
class someClass{
public:
subClass * pointer;
someClass(){
pointer = new subClass;
}
subClass * getMe(){
return pointer;
}
};
int main(){
someClass * one = new someClass;
subClass * two = new subClass;
one->getMe() = two;
}
I'm a bit new to c++ so the problem might be horrible simple. Any help is much appreciated.
The pointer that you return from the function is a copy of the pointer in the object. It is a temporary, you cannot assign to it. Even if you could assign to it, it would do no good, because it is no longer connected to the pointer in your object. If you want to be able to assign to the object's pointer after returning it from the function, you want to return the pointer by reference.
subClass *& getMe() {
return pointer;
}
You should also may want to consider adding a const overload in order to work on const objects. It might look like this:
subclass * const & getme() const {
return pointer;
}
The line
one->getMe() = two;
Is trying to assign the pointer at two to one->getMe(). But one->getMe() returns a temporary copy which you cannot assign to. If you want to return the pointer by reference and thus be able to change it then you can use the signature
subClass *& getMe();
as others have suggested.
That being said, you're exposing the inner workings of a class for all and sundry to see and modify, in particular pointers to objects on the heap which may or may not be deallocated correctly which is unwise.
This is a C++ class that I have made with n number of pointers.
class SomeClass
{
private:
int* ptr1;
int* ptr2;
...
int* ptrn;
private:
// constructors, destructors, and methods
};
During the initialization stage, I want to make all those pointers point to NULL (or make pointers point to NULL by default when they are declared) rather than doing so:
void SomeClass::MakePtrNull()
{
ptr1 = NULL;
ptr2 = NULL;
...
ptrn = NULL;
}
Is there any easy method of accomplishing this goal? I'm just wondering if there are any ways of avoiding typing n lines of ptr = NULL; in my function. Thanks in advance.
ADDED based on the answers that I have received so far:
Unfortunately, those pointers have to be separate, as they are used for different purposes. I made the names of the pointers as such just to make a point of what I'm trying to do, but each pointer has a completely different purpose. I guess I would have to make them point to NULL as I have done already. Thanks for your answers.
Instead of int *, create a smart-pointer-like class which works exactly like a int *, but default-constructs with NULL:
template <typename T>
class MyPointer {
T *p;
public:
MyPointer() : p(NULL) { }
MyPointer(T *o) : p(o) { }
operator T*() const { return p; }
// ...and the rest of the traditional smart-pointer operators
};
Then, use it in your class:
class SomeClass
{
private:
MyPointer<int> ptr1;
MyPointer<int> ptr2;
...
MyPointer<int> ptrn;
private:
// constructors, destructors, and methods
};
Every variable of the MyPointer<int> type will be automatically initialized correctly in SomeClass's constructors, without the need for any extra typing. If you did not forget or incorrectly implement any of MyPointer's methods, it will act exactly like a normal pointer, and have the exact same size and performance.
Why don't you use an array or a vector rather than creating n individually named pointers? Then you can do the nulling in a short for loop.
You can do this:
void SomeClass::MakePtrNull()
{
ptr1 = ptr2 = ptr3 = ... = ptrn = NULL;
}
First, the technique that does not work:
Calling memset to set the entire object to zero won't do. First, it'll cause a lot of trouble if your function has one or more virtual functions, and second, a null pointer is not guaranteed to be represented by a bit pattern of all zeros.
What I would probably do in your case is store the pointers in an array or a vector.
Then you can use the std::fill function to set them all to NULL. (Or you could use a loop if you prefer)
Of course, if you need to do this often enough, it may be worth writing a wrapper class which behaves as the pointer, but which sets it to NULL in its default constructor.
Or you could use boost::optional which works essentially like this. (although it is not specific for pointers)
I recommend you to do the following, if you have to keep the pointers separately (probably the most pressing need would be if the pointers can have different types)
class SomeClass {
struct Pointers {
int* ptr1;
int* ptr2;
float* ptrn;
} ptrs;
public:
void MakePtrNull();
};
void SomeClass::MakePtrNull()
{
// clears all pointers at once
ptrs = Pointers();
}
This does work, because value-initialization for classes that doesn't have a user declared constructor will value initialize all its members. Value initialization of a pointer will create a null pointer.
Why not use a default constructor:
SomeClass::SomeClass() : ptr1(NULL), ptr2(NULL), ...
{
}
You could also do:
ptr1 = ptr2 = ptr3 = NULL;
You could put the pointers into a struct and then memset() the struct when needed. The pointers are still separated, but you have the means of targeting them as a single unit without affecting the rest of your class. For example:
struct MyPointers
{
int* ptr1;
int* ptr2;
...
int* ptrn;
};
class SomeClass
{
private:
MyPointers ptrs;
...
};
void SomeClass::MakePtrNull()
{
memset(&ptrs, 0, sizeof(ptrs));
}
Use a vector for this (because by the sounds of it you won't need to ever edit the list in the future - and you need random access). You can do it like this:
class PointerList
{
private:
typedef std::vector<int*> IntPtrVector;
IntPtrVector m_ptrVec;
public:
PointerList()
{
m_ptrVec.reserve(5);
for (int i = 0; i < 5; i++)
m_ptrVec.push_back(NULL);
}
int* getPointer(int index)
{
return m_ptrVec[index];
}
void setPointer(int index, int* ptr)
{
assert(index <= 4);
m_ptrVec[index] = ptr;
}
};
EDIT
Though to be honest this reeks of ghettoness. Are you sure your problem requires this solution? If you elaborate more on your specific problem, in another question perhaps, I'm sure you can get some better answer on how to accomplish what you want more elegantly - rather then by creating a second problem.
I'm searching for a proper way to clean my pointers.
Here the example code:
class Parent {
protected:
int m_Var;
public:
Parent() : m_Var(0) {}
virtual ~Parent() {}
void PubFunc();
};
class Child : public Parent {
protected:
bool m_Bool;
public:
Child() : m_Bool(false) {}
virtual ~Child() {}
void ChildFunc();
};
void RemoveObj(Parent **ppObj)
{
*ppObj->PubFunc();
delete *ppObj;
ppObj = NULL;
}
int main()
{
Parent* pPObj = NULL;
Child* pCObj = NULL;
pPObj = new Parent();
pCObj = new Child();
RemoveObj(&pPObj);
RemoveObj(&pCObj); // This is line 33
return 1;
}
But the compiler gives error:
classes.cpp:33: error: invalid conversion from ‘Child**’ to ‘Parent**’
classes.cpp:33: error: initializing argument 1 of ‘void RemoveObj(Parent**)’
There are soo many ways to handle memory correctly.
The one close to your example would be:
template <typename T>
RemoveObj(T **p)
{
if (p == NULL) return;
delete *p;
*p = NULL;
}
Additionally you might want to use std::auto_ptr instead. It would look like:
int main()
{
std::auto_ptr<Parent*> pPObj(new Parent);
std::auto_ptr<Child*> pCObj(new Child);
// no deletes needed anymore
To put it simple :
Child is a subclass of Parent so that means that Child* can be substituted with Parent*
BUT
Child* is NOT a subclass of Parent* so that means that Child** can't be substituted with Parent**
"Child" and "Child*" are not the same types.
What you need to do is nullify all the pointers to the object you just deleted. The idea of pointers is that there will be more than one pointer storing the address of the same object. If not, there is little reason to use a bare pointer, and so the pattern you're trying to capture is not very useful - but you are far from the first person to try this. As other answers have mentioned, the only way to deal with pointers is to carefully control access to them.
The title of your question is absolutely correct! There's a good reason for it. A pointer identifies a location that stores an object of a specific type. A pointer to a pointer gives you the ability to change what object a pointer points to.
void Foo(Parent **pp)
{
*pp = new OtherChild();
}
Your Child class derives from Parent, and so does my OtherChild class. Suppose the compiler allowed you to do this:
Child *c = 0;
Foo(&c);
You expected that to work, but if it had, then we would now have a Child pointer c that in fact pointers to an instance of OtherChild. Who says those two types are compatible?
Again, this is a very frequent misunderstanding - it crops up repeatedly here for other languages, especially with regard to List<Parent> and List<Child> in C#.
You don't need a wrapper for delete, keep it simple:
int main()
{
Parent* pPObj = NULL;
Child* pCObj = NULL;
pPObj = new Parent();
pCObj = new Child();
delete pPObj;
delete pCObj; // This is line 33
return 1;
}
And remember you will run into issues deleting array type objects with your RemoveObj (since you are always using a scalar delete). An alternative is of course to pass a flag around to indicate you want delete []. But as I said: KISS.
If your problem is dealing with memory and resources, the best advice would be to forget your approach completely and use smart pointers. std::auto_ptr or boost::shared_ptr would be a start point.
If you hold all your heap allocated resources with smart pointers your code will be more robust.
You can find some useful information from the book < C++ common knowledge> Item 8. Pointers to Pointers.
Probably the most simple solution I have found:
#define __REMOVE_OBJ(pObj) RemoveObj(pObj); pObj = NULL;
And just call this one:
__REMOVE_OBJ(pPObj);
__REMOVE_OBJ(pCObj);
But I don't really like it myself...
From discussion on make shared_ptr not use delete
Shared pointer will ensure you cleanup when you should and that you don't access something that is destroyed. Further you can specialise and provide an alternate destruction method.
boost::shared_ptr<T> ptr( new T, std::mem_fun_ref(&T::deleteMe) );