This is my first post in any forum so please bear with me.
I am writing a C++ program that utilizes a custom class 'Book' with member variables such as title, author and other variables that are stored in strings. Amongst these member variables is a vector for storing objects of type Review (which is another custom class). Now in my driver file (where the main() is located) needs to access that vector (the Reviews vector in each Book object) and make changes to it as well. I realized that I need to utilize a pointer of type vector
(eg.
vector pointerName
). So I added another member variable to the Books class which is a pointer. The problem I am facing is to point that pointer to the vector. Where can I make this assignment? I tried de-referencing it and pointing it to the vector in the default constructor for the object, but that causes my program to crash at run time without throwing an exception. The line I put in the constructor is
*pointer = vector_of_reviews;
I am new to this forum and still learning how to go about posting here so please bear with me if I have made a mistake in my post or if I was unclear or insufficient with my information. Please let me know if I need to post or say anything more to make my stance clear.
Thank You.
To assign a pointer to 'point to' an instance of an object use pointer = &vector_of_reviews.
The & operator gets the address of something, and it's this that you want to assign to the pointer.
*pointer = vector_of_reviews dereferences the pointer (obtains the actual object 'pointed to'). This would more than likely crash if the pointer is yet to be initialised. If the pointer was valid this would perform a value assignment, ie. invoke the vector class's assignment operator.
Related
I have seen the following construction in many code reviews:
ClassX *pObj;
ClassX obj;
pObj = &obj; //obj is not used in the rest of the code
Is the line below only used for initialization purposes?
pObj = &obj;
Why is it not initialized to NULL?
pObj = &obj; here pObj is pointer and it is pointing to obj.
Like below,
Note: Only for illustration purpose I have chosen address of obj,pObj as 0x1000,0x2000 respectively.
Why they do not initialize to NULL.
pObj can be initialized to NULL but eventually overwritten by pObj = &obj and hence no side effect occurs. But access to pObj before assignment causes UB.
pObj is a pointer to a properly initialised instance that can be used by the rest of the function or any called functions. NULL would mean there is no instance, a very different thing.
But why would you do this? One answer is that the rest of the code uses pointers and the author feels happier using pObj than using &obj.
Another may be that the pointer later gets assigned to a real object "usually". You didn't show us the later code so we have to speculate (or downvote). Perhaps the author thinks that having a valid temporary is less prone to crashes than having a null ptr if the assignment fails and the later code that uses the pointer is allowed to run, but this really is lazy programming, paying to initialise an object you never intend to use. If the real object is dynamically allocated, then the pointer might be valid outside the scope of this code, but the default instance would not be.
Sometimes construction/copy/move of objects is costly or impossible; thus pointer ClassX* pObj; can serve as a tool to quickly change target - as copying pointers is simple and cheap overall.
Say, in a loop pObj is frequently used and sometimes you need it to point to one object, then to another, and carryover it to next iterations. Or you have some complex rules that determine to which variable the pointer points to.
If one could've simply used obj instead of the pObj in the method without any issues - then it is simply poor coding practices to use pObj. Some might use it to save & when passing pointers... but that's barely an excuse. Regardless, I don't see much harm except for clutter.
Or they simply copied the code from elsewhere (that was also copied from another place...) without dwelling on it much as to why it is written in this way.
Okay, so my situation is really complex to a relativity new person to C++ like me. I'm making a game (AGK library) and I have a framework class that is the base class for all of the game's objects to have standard functions like frameEvent and such that are to be overwritten by the child object.
That's all fine and dandy, and I've gotten about 70% through development, but I ran across one vital problem.
To make life easier while processing the game, each object that is a part of the game is just a pointer in a vector of type Framework*. Framework being the base class. I was told that making it a pointer allows me to have child objects of different types as long as they're a pointer as well. So far it's worked out.
Every frame, the global object runs through the vector of all the objects and runs their
frameEvent
frameEndEvent -- Can't be overriden
drawEvent
They're really just functions. So in the enemy's bullet class, I need to check if it collides with oPlayer, so I have a functions in the global class (The global class is passed to the objects in their frame event so they can communicate with other objects.) that grabs a given object.
It searches through all of the objects to find the parameter object -- so if I pass new oPlayer, it will return the real oPlayer pointer in the game.
When the bullet collides with the player, it needs to lower the player's health and then destroy itself. So at the create function for the bullet, it creates a dummy player then locates the real one using the global class function. The code is
//Find the player
oPlayer* tempPlayer = new oPlayer;
playerChecker = ObjGlobal->classToObject(tempPlayer);
tempPlayer->objectDestroy();
That code works, but it needs playerChecker to be type Framework* because that's what classToObject returns. But when I later use that pointer, I can't access the player's members even though that's the player's pointer.
playerChecker->hitPoints--;
hitPoints is exclusive to oPlayer. I think it's called object splicing or slicing, but I thought that's what using pointers fixed.
So I tried to make playerChecker type oPlayer*, but it says that Framework* can't be converted to it. So I have no idea what to do.
Any help is greatly appreciated.
Your Framework* from classToObject can be downcast to a oPlayer* using a dynamic_cast, like so:
oPlayer* playerChecker = dynamic_cast<oPlayer*>(ObjGlobal->classToObject(tempPlayer));
if (oPlayer) {
// cast succeeded, do stuff with the pointer
}
dynamic_cast is a C++ type cast operator just like the C-style cast, with some special properties. It is specifically designed to convert between pointers or references to polymorphic objects (like your oPlayer, which can be treated as both a Framework and an oPlayer). It also adds a run-time check which verifies that the object you're trying to downcast is indeed an instance of the class you're trying to cast to. If it isn't, it will return a null pointer, or in the case of references, throw an exception.
Your code will also work with a C-style cast or a static_cast (which is much like a C-style cast with compile-type type checking).
static_cast<oPlayer*>(ObjGlobal->classToObject(tempPlayer)) // static_cast
(oPlayer*)ObjGlobal->classToObject(tempPlayer) // C-style cast
These have less overhead because of the lack of a run-time check, but that also means that they are unsafe unless you can guarantee that the pointer you're casting points to an object of the correct type. Also, since dynamic_cast has a very specific use, it makes it clear what your intent is.
What's the error you're getting? Please post this, as we can't offer much help otherwise.
If I had to guess, you forgot to add public: to your class FrameWork. This, or you don't have setters/getters in your class.
I'm using box2d and as you already may know, it holds a void* to an object which i can use as reference when collisions occur between different entities. Problem is that the original item is saved inside a shared_ptr since the ownership is unknown and different classes (example player class) can 'equip' another class (weapon).
I'm just wondering if its possible to put this pointer inside a shared_ptr and refer to the same object as the original one?
This is an example:
std::vector<std::shared_ptr<Environment>> listEnvironment;
listEnvironment.push_back(std::make_shared(new Weapon()));
//takes a void pointer
box2d->userId = listEnvironment.back().get();
//some shit happens somewhere else and collision occurs and I get pointer back from box2d's callback:
Environment* envPtr = static_cast<Environment*>(box2d->userId);
As you can see envPtr is going to cause trouble.
Is there a way to refer to the old smart-pointer and increase its reference value?
PS:
In actuality every class creates an box2d body which holds a 'this' pointer so i don't actually have the address to the smart-pointer either. The example above is kind narrowed down to give you a hint of the problem i'm facing.
Best regards
nilo
If Environment has std::enable_shared_from_this<Environment> as a parent class then, yes. Just call envPtr->shared_from_this().
I'm currently learning about virtual functions, and in this particular lesson it creates an array of object pointers firstArray[5], and calls functions from these objects. Until now, whenever I wanted to call a function func() from an object foo, I would write foo.func(). Now that I'm using virtual functions and this array, the book has switched to this method: firstArray[0]->func(). The book doesn't do a great job at justifying this switch, could someone please explain? I see that when I try to use firstArray[0].func(), I get this....
error: request for member 'func' in 'firstArray[0]', which is of non-class type 'sampleClass*'.
Is it simply because I'm trying to call a function from a pointer, not an actual object? I've been learning C++ for several months now, and for whatever reason pointers still trip me up sometimes. Any clarification would help.
EDIT:
I think the part that got me mixed up is this: I can create a pointer to a base object class with base *ptr;. Then, I can set that pointer by creating a new object from a derived class by saying ptr = new derived;. This is where I get confused. If I were to create an int* ptr;, and I wanted it to point to a integer I create, I couldn't say ptr = int j. If ptr is really just an address, why do these two examples work differently? I guess I don't understand the "new" mechanic very well either.
That doesn't have anything to do with virtual functions. If you have a pointer you need operator-> to deference and access the object it's pointing to....
You could still use the operator. (dot) to access the members/functions if you dereference first:
(*foo).func()
A pointer to an object just holds the address where the object is held in memory.
So if you have a variable which is a pointer to some type, it actually holds a number.
If you want to use the object, you need to call the object it is pointing to, which is as I said by using either operator* or operator. (dot).
I have a C++ class where I have a dynamically-allocated array of pointers to structs. I have a member function to "add an item" to this array by assigning an index of the array to the pointer to a dynamically allocated instance of the struct.
I have sort_arr initialized with sort_arr = new node *[this->max_items];.
In my assignment function I have sort_arr[this->num_items] = item; where the pointer is being passed as an argument with node *item.
In this function, I am able to access a member variable using (*sort_arr[i]).key_a (where i is the index), but once another item is added, this reference is no longer valid and causes a seg fault.
Is the pointer being deallocated, and if so, is it possible to prevent this?
EDIT: Sorry for the ambiguity here. I am trying to understand the problem generally and not specifically (in a pedagogical sort of way). I was hoping it was a problem with my conceptual approach. Given that it probably isn't, here are some more details:
node is defined as node **sort_arr; in the class declaration and then initialized by the constructor as sort_arr = new node *[this->max_items];. The insert method of the class executes: sort_arr[this->num_items] = item;, where item is passed with node *item.
It seems that after an item 'n2' is inserted after 'n1', 'n1' is no longer accessible via the reference (*sort_arr[num_items]).key_a. key_a is a member variable of the node struct.
EDIT 2: node *item is dynamically allocated outside of the class (in the main function).
The code you posted looks basically correct (if not the best way to do this sort of thing), but I can't tell what key_a is, or what context you are calling it in. Because of that, it's hard to tell exactly what the problem is. Posting the entire body of your function might be useful.
The only way something you allocated via new will be deallocated is if you (or some code you call) explicitly calls delete. That's pretty much the whole point of dynamic memory allocation, to allow your objects to live after the stack frame gets popped off.
My best guess with the current information is that you're trying to access a local value that got allocated on the stack after returning from the function. For example, this would cause a problem:
some_type* some_function(int i)
{
// ...
some_type p = (*sort_arr[i]).key_a; // p is a copy of key_a, allocated on the stack
// ...
some_type* result = &p;
return result;
}
In this scenario, p would be okay to return directly (if you changed the return type to some_type instead of some_type*), but you can't return a pointer to a local value. The local value is no longer valid after the function exits. This often causes a segfault.
Make sure that this->num_items as well asi is less than this->max_items and greater than -1, as this could be the cause of seg-fault.
Don't use dynamic arrays if it isn't for lecturing. Use a simple and save std::vector. It handles nearly everything that could go wrong. Try with that and see if there's still a seg-fault.
As noted, the code does appear to be correct. The problem was unrelated to the referenced code. I had been debugging some memory leaks and was deleting the referenced items, which was in turn causing the problem (quite obviously now that I see that).
I appreciate everyone's help and I'm sorry if I drove anyone crazy trying to find what was wrong.