I have a program where users can create Frames using Lua command such as:
frm=Frame.new()
the above-mentioned command shows a frame to the user. Behind the scenes the C++ wrapper is as follows:
Frame* Frame_new(lua_State* L)
{
int nargs=lua_gettop(L);
Frame* wb=0;
if(nargs==0){
//Omitted
wb=mainfrm->GetFrame();
lua_pushlightuserdata(L,(void*)(wb));
int key=luaL_ref(L, LUA_REGISTRYINDEX);
wb->SetLuaRegistryKey(key);
}
return wb;
}
Since the frame is shown to the user, the user can close the frame by just clicking on the close button provided by the operating system. This generates a close event and it is handled as follows:
void Frm::OnClose(wxCloseEvent& evt)
{
//Omitted for brevity
int LuaRegistryKey=GetFrame()->GetLuaRegistryKey();
lua_rawgeti(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey);//userdata
Frame* wb1=(Frame*)lua_touserdata(glbLuaState,-1); //userdata
lua_pop(glbLuaState,1); //
lua_getglobal(glbLuaState,"_G"); //table
lua_pushnil(glbLuaState); //table key
while (lua_next(glbLuaState,-2)) {//table key value
const char* name = lua_tostring(glbLuaState,-2);//table
if(lua_type(glbLuaState,-1)==LUA_TUSERDATA){
Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1);
if(wb2==m_Frame){ //this part doesnt work
lua_pushnumber(glbLuaState,0);
lua_setglobal(glbLuaState,name);
lua_pop(glbLuaState,1);
break;
}
}
lua_pop(glbLuaState,1); //table key
} //table
lua_pop(glbLuaState,1); //
if(m_Frame==wb1) {delete m_Frame; m_Frame=0; wb1=0;}
if(wb1) {delete wb1; wb1=0;}
luaL_unref(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey );
}
Now the goal is when user closes the frame the variable created by frm=Frame.new() should be nil so that user can not call one of its methods, such as frm:size() which crashes the program.
In the above C++ code for handling the close event, wb1 and current frame has the same memory address. Now to my understanding all I need to do is search the global table for the userdata type Frame and compare the memory addresses so that I know I am choosing the right frame and then set it to nil.
However, Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1); returns a completely different address from wb1, therefore I cannot know which variable of type frame I am referring to.
To my understanding wb2 has a different memory address possibly due to 3 scenarios:
1) frm is a full userdata
2) frm is inside global lua table, therefore has a different address (although this doesnt make sense to me as I pushed the address of Frame in C++).
3) I am thinking completely in the wrong way or cant see something simple.
Now to my understanding all I need to do is search the global table for the userdata type Frame and compare the memory addresses so that I know I am choosing the right frame and then set it to nil.
Your understanding is wrong.
First, you did not return userdata to Lua. You returned light userdata. That's different. The lua_type of light userdata is LUA_TLIGHTUSERDATA.
Second, even if you fixed that problem, you're not iterating through tables inside the global table. So something as simple as this would confound you:
global_var = {}
global_var.frame = Frame.new()
Lua code should be able to store its data wherever it wants. And if it wants to store some userdata in a table, who are you to say no?
Third, even if you iterated through every table accessible globally recursively (with protection from infinite loops), that wouldn't stop this:
local frm = Frame.new()
function GlobalFunc(...)
frm:Stuff();
end
Because Lua has proper lexical scoping, GlobalFunc will store a reference to the frm local internally. And since frm is a local variable, you cannot get at it just from iterating through globals.
Generally speaking, if you give a value to Lua, it now owns that value. It can do whatever it wants, and it's generally considered rude to break this contract.
Though it's not impossible. The way to handle it is by using an actual userdata rather than light userdata. Each regular userdata is an object, a full allocation of memory. Inside that allocation you would store the Frame pointer. When it comes time for that Frame to be destroyed, all you have to do is set the Frame pointer inside the userdata to NULL.
Conceptually, it's like this in C++:
struct FramePtr
{
Frame *ptr;
};
Lua would be passing around a single allocation of FramePtr. So if you set that allocation's FramePtr to NULL, everyone sees it. No iterating through global tables or somesuch.
Of course, accessing the Frame from a FramePtr requires an extra indirection. However, by using full userdata instead of light userdata, you can also attach a proper metatable to it (light userdata doesn't get per-object metatables; every light userdata shares the same metatable).
Related
I'm working on a diagram visualisation tool and I ran into an issue where my QGraphicsScene does not display a shared_ptr<DiagramItem> when a raw pointer obtained via .get() is passed to scene->addItem().
Subsequent check via scene->items() shows that my DiagramItem is not a part of the scene. My guess is that it got freed as the refcounter on the shared_ptr will be zero after leaving the scope of the testing function...
But that was the testing case. In my actual code I'm using a shared_ptr that I got from elsewhere and is definitely present in memory with a non-zero refcounter. I get the raw pointer of that and pass it to scene->addItem(). It is also not displayed, but this time it is present in scene->items(). So why is it not being drawn?
If I switch from using shared_ptr<DiagramItem> to DiagramItem* then the issue disappears and everything is displayed properly. But due to limitations from the rest of the project, I cannot easily abandon smart pointers here, nor do I want to.
Did I run into some kind of memory limitation or am I doing something wrong?
I already tried calling show() and update() on the item and increasing the scene size in case the item doesn't fit (it does). I also tried breakpointing the paint() method, but that one doesn't get called at all.
I found a possibly related question here where similar behaviour occurs due to the object going out of scope and being deallocated, but that doesn't seem to be the case with my actual DiagramItem.
class DiagramItem : public QGraphicsItem
{
...
}
//Create scene
auto scene = new QGraphicsScene(nullptr);
//Item is created OR obtained from elsewhere
auto item1 = std::make_shared<DiagramItem>(nullptr, QString("aaa"), true);
auto item2 = GetDiagramItem(...);
//Raw pointers get passed to addItem
scene->addItem(item1.get());
scene->addItem(item2.get());
//Item1 is not present at all (directly created DiagramItem)
//Item2 is present but invisible (DiagramItem passed from elsewhere)
//myItem gets Item2
auto myItem = scene->items()[0];
...
The UI system in my program currently works by assigning function pointers of the type void(*)() to trigger elements (quads on the screen, keys on the keyboard) with a specifiable call condition which will be compared to the actual condition of the key (using GLFW), mouse button or cursor every frame to determine whether the callback function should be called.
A condition for a key could be KeyCondition(PRESS, LEFT_SHIFT) which would call the callback bound to the key if the key was pressed while left shift is being held down.
My problem is that I can only assign these buttons functions of the type void(*)(), which disables me to pass arguments to a button callback.
If for example I wanted to make a button light up when the cursor hovers over it, I would have to create a designated function void highlightButtonA() which sets the color of button A to a higher value internally, while I would of course much rather be able to set the callback to something like void offsetColor(unsigned int buttonIndex, float r, float g, float b, float a) and pass individual parameters to each callback.
Is there any way to do this? Is there some function pointer which can point to a function of any shape and will store parameters somehow? How much should I worry about the performance of these solutions? My program has to be able to handle multiple key/button presses per second and still be stable, as it is a fast-paced shooter game.
You can use non-capturing lambdas that decay to function pointers, something like this:
button.OnMouseHover([]{ offsetColour(buttonIndex, r, g, b, a); });
just remember that buttonIndex and other args to offsetColour should be literals as the lambda cannot capture variables from the enclosing scope.
I currently have a project using DirectX11, that generates random terrain based on the Hill algorithm. I have a set up where by you can change the inputs on the terrain (seed, number of hills etc) and then reinitialize and watch the terrain get generated hill by hill. The issue with this is that (as you would expect) there is a large FPS loss, but also things like the camera will stutter when attempting to move it. Essentially, what I want to do is create a thread for the terrain hill step, so that the generation doesn't interfere with the frame time and therefor the camera (so the camera can still move seamlessly). I've looked at a few resources but I'm still not understanding threads properly.
Checking when to reinitialize the terrain, during the update method:
void CThrive::Update(float frameTime)
{
CKeyboardState kb = CKeyboardState::GetKeyboardState(mWindow->GetHWND());
mCamera->Update(kb, frameTime);
if (mGui->Reint())
{
SafeDelete(mTerrain);
mTerrain = new CTerrain(mGui->GetTerrSize(), mGui->GetTerrMin(), mGui->GetTerrMax(), mGui->GetTerrNumHills(), mGui->GetTerrSeed());
mNewTerrain = true;
mGui->SetReint(false);
}
Calling method to generate new hills, during the render method:
void CThrive::Render()
{
if (mNewTerrain)
{
reintTerrain();
}
MainPass();
}
Method used to add to the terrain:
void CThrive::reintTerrain()
{
if (!mTerrain->GenerationComplete())
{
mTerrain->GenerateStep(mGraphicsDevice->GetDevice());
}
else
{
mNewTerrain = false;
}
}
I assume I'd create a thread for reintTerrain, but I'm not entirely sure how to properly make this work within the class, as I require it to stop adding hills when it's finished.
Thank you for your help
Use std::thread for thread creation. Pass pointer to thread's entry point to its constructor as a lambda of member function pointer. Instances of std::thread may reside in the private section of your class. Accesses to shared object's fields used by multiple threads should be protected by fences (std::atomic<>, std::atomic_thread_fence) in order to avoid cache coherency problems.
In UE4 I am working on a Puzzle Block game in my Graphics 2 class. Our professor and our class is learning about UE4 together. Our class as a whole is a little confused about one thing in the C++ code and my professor said he would try to figure the answer out himself, but I figured I would jump start our next class with information that I find here.
Okay so in the BlockGrid.cpp file this section of code is used to create the blocks.
void AMyProject2BlockGrid::BeginPlay()
{
Super::BeginPlay();
// Number of blocks
const int32 NumBlocks = Size * Size;
// Loop to spawn each block
for(int32 BlockIndex=0; BlockIndex<NumBlocks; BlockIndex++)
{
const float XOffset = (BlockIndex/Size) * BlockSpacing; // Divide by dimension
const float YOffset = (BlockIndex%Size) * BlockSpacing; // Modulo gives remainder
// Make postion vector, offset from Grid location
const FVector BlockLocation = FVector(XOffset, YOffset, 0.f) + GetActorLocation();
// Spawn a block
AMyProject2Block* NewBlock = GetWorld()->SpawnActor<AMyProject2Block>(BlockLocation, FRotator(0,0,0));
// Tell the block about its owner
if(NewBlock != NULL)
{
NewBlock->OwningGrid = this;
}
}
}
The confusion starts with the following line in this function:
AMyProject2Block* NewBlock = GetWorld()->SpawnActor<AMyProject2Block>(BlockLocation, FRotator(0,0,0));
Each time it looks like it is rewriting NewBlock for each new block in the puzzle. Our problem is for the game we are creating, which is a Lights Out game, is if NewBlock is being continually being rewritten, then how is it keeping track of the addresses for the information to the blocks that are being displayed on the screen? This could be fixed by simply creating an array to store the information, but if the information is still being kept somewhere this would be inefficient. So how can we access the information for the blocks if NewBlock is being overwritten with each loop without making an array to inefficiently store the data?
THANKS!!!! :)
#Mathew's comment has the right idea, when you use SpawnActor, Unreal does a whole bunch of behind the scenes stuff but essentially creates your actor inside the world and manages its lifetime. (For example, to remove your actor from the level, you would need to use:
MyActor->Destroy();
Rather than the C++ method:
delete PtrToActor;
This handles removing it from the scene, updating collision volumes etc. before actually deleting the actor.
To your code, you are of course overwriting the pointer to your block, so the block itself is left untouched. You can use the TActorIterator<T> iterable to loop through all actors of a type which would save you having to store an array yourself. You would do something like this:
for (TActorIterator<AMyProject2Block> ActorItr(GetWorld()); ActorItr; ++ActorItr )
{
AMyProject2Block* PtrToActor = *ActorItr;
}
Where here the PtrToActor will point to each instance in turn as the loop advances.
However, it isn't really inefficient (and in many cases, is efficient) to store your own separate array of pointers. It is only a small memory cost (since it is just pointers) and might be faster as you don't have to filter the actors to find the one you want. In either case, it is a much of a muchness so you should choose whichever one feels more logical.
In your example, I'd keep them in 2D data structure so you can access them via their position rather than just getting an un-ordered list of them from the engine.
I used one scene and many layers for my game.
when user go to another game screen I remove current layer from scene , delete current layer, set current layer = NULL, then create a new layer, add it to the scene
void UIManager::openScreen(int screenId){
m_currentScreen = screenId;
CCLayer *newLayer;
if(screenId == MENU_SCREEN){
newLayer = new MenuLayer();
}else{
...
}
if(m_currentLayer != NULL){
m_scene->removeChild(m_currentLayer, true);
delete m_currentLayer;
m_currentLayer = NULL;
}
m_scene->addChild(newLayer);
m_currentLayer = newLayer;
}
On some layers, i call some CCHttpRequest with callback:
setResponseCallback(CCObject* pTarget, SEL_CallFuncND pSelector)
And i use "this" to pass to "pTarget", it means first parameter for this callback is my layer which defined a SEL_CallFuncND selector.
The problem is when user switch between screens(layers) to quick, but some slow CCHttpRequest still not completed, and the response callback will be called after UIManager delete the layer then my game crash :(. I don't want to lock the screen and force use wait the http request complete. User should can abort loading a screen and switch to the next screen they want.
So should i call "delete m_currentLayer" instead of m_currentLayer->release()?
As i know, release will decrease the reference count, i just want to make sure "noone" use the m_currentLayer rather than m_scene so i used "delete". But i'm not sure it is correct way.
If i use release function in this case, i worry some places in code use the layer and increase the retain count of the layer, is this can make a leak memory issue?
if m_currentLayer->retainCount() = 4 and i call "delete m_currentLayer", then what will happen with m_currentLayer?
I'm confusing with these issues, please someone give me an advide.
Thank you very much!
You should not delete your nodes manually. It can cause a bunch of errors. Reference
counting convention is to call retain when you need to be sure that object still exists and call release when you do not need this object.
Use retain and release only inside object, that really needs other object to exist. In any other case you can use assign property(do not retain object and check it is not NULL) before doing something with it. If some object(let's call it a), that is not yours(CCNode, for example) retains the other object(let's call it b), deleting b manually can cause bad access error, because a will be sure that b still exists. And can call something like b->doSmth()
Your m_currentLayer will be deleted, but it can cause errors because retain count 4 means that 4 objects can cause bad access error described above.