Retrieve object instance from map - c++

I'm new to C++ and I'm trying to make a little game. I have this class named "UnitController" which stores multiple instances of the class "Unit" in a map. The class also has a method "getUnit" which should return one of the stored units.
It seems this method is only partially working. I think I get a copy of the unit instead of the requested instance.
Could anyone point me int the right direction?
#include "UnitController.h"
#include "Unit.h"
using namespace ci;
using std::map;
UnitController::UnitController()
{
}
void UnitController::addUnit( Vec2f position )
{
Unit mUnit = Unit();
mUnit.setup( position );
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
}
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
void UnitController::update()
{
for( map<int,Unit>::iterator u = Units.begin(); u != Units.end(); ++u ){
u->second.update();
}
}
void UnitController::draw()
{
for( map<int,Unit>::iterator u = Units.begin(); u != Units.end(); ++u ){
u->second.draw();
}
}

The method:
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
is returning a, possibly default, copy of the element with index 0 (do you mean to ignore k?). If you wish to avoid a copy being returned then return a reference instead to the element at index 0, not to the local variable selectedUnit:
Unit& UnitController::getUnit( int k )
{
return Units[k];
}
If the entry keyed by k is removed from the map then a caller that has a reference to the Unit of the entry now has a dangling reference, use of which is undefined behaviour. There a few things to consider to try and avoid this:
Does a client of UnitController require direct access to a Unit in the map? If not and the client only requires to update certain attributes of a Unit then modify the UnitController interface to support updates to Unit without providing a client direct access.
If a client does require direct access then consider using a std::shared_ptr<Unit> instead of a Unit for entry value type (and don't return by reference in this case). This would address the dangling reference problem but what does it mean for caller to have access to a Unit that is no longer in the UnitController?
operator[] will create an entry in the map for a key that does not currently exist:
Inserts a new element to the container using key as the key and a default constructed mapped value and returns a reference to the newly constructed mapped value. If an element with key key already exists, no insertion is performed and a reference to its mapped value is returned.
If you wish to not have this behaviour then use find() and decide on what action to take if an entry for key k does not exist.

In this code:
Unit UnitController::getUnit( int k )
{
Unit selectedUnit = Units[0];
return selectedUnit;
}
you return Unit by value, so you actually get a copy of the original Unit.
(Note also that you seem to have a bug, since you use 0 as key, instead of parameter k...)
If you want to modify the original Unit (i.e. the one stored in the map), you can return by reference (Unit &):
Unit& UnitController::getUnit(int key)
{
return Units[k];
}
As a side note, you can simplify your insertion code. Instead of using std::map::insert() method:
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
you can just use std::map::operator[] overload:
Units[ ...the key here... ] = mUnit;

You will indeed receive a deep copy of Unit.
Consider creating a reference counting pointer (aka smart pointer) encapsulating a Unit and set that to the value type of the map.

of course you get the copy. consider this:
void UnitController::addUnit( Vec2f position )
{
Unit mUnit = Unit(); // you create local instance of Unit
mUnit.setup( position );
// you add it to the map - actually the copy is created and stored in map
Units.insert( std::pair<int,Unit>( Units.size()+1, mUnit ) );
// mUnit is destroyed after the function exits
// your map would now contain a destroyed object if it wasn't a copy
}
Besides your getUnit method also returns a copy. this might be OK or not, depending on what the client does with it. if it changes the state of returned unit instance, then it will not be reflected in the copies withing the map.
You might want to use map<int,Unit*> but then you need to take care of lifetime of the original objects. You can't destroy it because pointer will point to destroyed object. Therefore, a proper solution is to use shared_ptr<Unit>
However, there are other problems with your design. You store the current size + 1 as the map key, which means that you use it as an index. Why not just use std::vector<shared_ptr<Unit>> instead?

Related

what /can/ you return from a function .. and expect it to be alive at arrival?

Once again I got cought on expecting a function to return a proper value and then be disapointed .. getting odd behavior and misleading debug-information instead.
It's fairly well known, that you cannot return a local variable from a function and expect it to arrive as you would expect. Testing
int i=2;
int k=4;
return make_pair<int,int>(i*i,k*k);
Does indeed return something respectable. But using more elaborate objects than simple types seems to catch me every time.
So, is there any formality that I can use for discriminating on what can and what cannot be returned safely from a function?
----------- added on edit: ------------
Here is the example that does not work, taken brutally out of context.
Problem-context is a (to be GUI) tree of rectangles for the screen.
Class node inherits from a base (rectangle) containing 3 pointers to plain types (again, used to make values stick) .. the base uses new in constructor
pair<node,node> node_handler::split( vector<node>::iterator& this_node, double ratio, bool as_horizontal ){
//this_node becomes parents to the split-twins
this_node->my_ratio=ratio;
double firstW, firstH;
double secW, secH;
glm::dvec2 afirst, asecond;
if(as_horizontal ){
firstW = *this_node->plWidth*LETTER_PIXEL_WIDTH;
firstH = *this_node->plHeight*LINE_PIXEL_HEIGHT*ratio;
afirst = *this_node->pPoint;
secW = firstW;
secH = LINE_PIXEL_HEIGHT*(*this_node->plHeight)*(1.0d-ratio);
asecond= afirst+glm::dvec2(0.0d, firstH);
}
else{
firstW = ratio*(*this_node->plWidth)*LETTER_PIXEL_WIDTH;
firstH = *this_node->plHeight*LINE_PIXEL_HEIGHT;
afirst = *this_node->pPoint;
secW = (1.0d*ratio)*(*this_node->plWidth)*LETTER_PIXEL_WIDTH;
secH = firstH;
asecond= afirst+glm::dvec2(firstW,0.0d);
}
return make_pair<node,node>( node(afirst ,firstW, firstH) , node(asecond ,secW, secH) ) ;
}
Technically, you can return anything from a function.
Now when you return a pointer or a reference to something that is only local, then you have a problem.
Solutions:
Return copies (OK with copy elision anyway)
Return shared_ptr<>/unique-ptr<> for something that must not be copied.
Return only basic types and pass to the function a reference to an object that might be modified.
Do not create something in the function that needs to be manually destroyed layer (say, a pointer created with new).
It's dawning on me, that classes containing pointer-members reasonably has to have custom copy/assignment operators. I never got to grips with the "rho" variable referred to in the books I read at the time ... "right_hand_object" it must be! That's my epiphany. It was following the business of the constructors and your talk of copyable objects that squeezed this old rho-problem of mine.
I'm sorry for having spread my frustration on you.

Delayed instantiation in C++

I'm trying to create a variable without instantiating the object.
In Python it would look like this:
graph = mymap[c] if c in mymap else Graph()
So I basically check if I already have that graph otherwise I create it. My understanding is that if I declare the following in C++ it will call the constructor and be wasteful.
Graph g;
So I'm trying to use pointers to avoid this "waste":
Graph* g;
if (graphs.find(c) == graphs.end()){
g = new Graph();
graphs[c] = *g;
} else {
g = &(graphs[c]);
}
std::cout << g << std::endl;
std::cout << &(graphs[c]) << std::endl;
The problem is that the addresses printed in the end do not match. In fact, my tests show that something weird is happening like a new instance of Graph is being created every time.
What am I doing wrong?
You actually don't have to do anything fancy here. You can simply do
Graph* g = &graphs[c];
The reason is that map::operator[] has the following behavior:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.
Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:
On this line:
graphs[c] = *g;
You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.
graphs[c] = ...
This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.

Why can't I push_back an object into a vector of objects that belongs to another class?

What I'm trying to do here is to add Voter to a vector that belongs to RegLogBook and, RegLogBook is an object that is owned by my Election class. I don't know what I'm doing wrong here, the Voter object is not being added to the vector. The relevant codes are below, I've removed all the unnecessary parts.
Election.h
class Election
{
public:
Election();
~Election();
RegLogBook getRegLogBook();
private:
RegLogBook* _regLogBook;
};
Election.cpp
Election::Election()
{
_regLogBook = new RegLogBook();
}
RegLogBook Election::getRegLogBook() {
return *_regLogBook;
}
RegLogBook.h
class RegLogBook
{
public:
RegLogBook();
~RegLogBook();
vector<Voter*> getVoterList();
private:
vector<Voter*> _voterList;
};
RegLogBook.cpp
vector<Voter*> RegLogBook::getVoterList() {
return _voterList;
}
Committee.cpp register voter method
void Committee::RegVoter(RegLogBook logs) {
Voter *newVoter = new Voter();
logs.getVoterList().push_back(newVoter); //The voter is not added to the list
}
I call this in my main()
Election *Election2018 = new Election();
Committee com1 = new Committee();
com1.RegVoter(Election2018->getRegLogBook());
RegLogBook::getVoterList() returns your _voterList by value. That means it copies the whole vector and returns it. Then you add elements to that copy.
To fix this, simply change your
vector<Voter*> RegLogBook::getVoterList()
to
vector<Voter*>& RegLogBook::getVoterList()
// ^ notice the reference part
There is another problem that I initially missed. In your Committee::RegVoter method, you take the argument by value. That means the method will be invoked with a copy of your RegLogBook. You should also change
void Committee::RegVoter(RegLogBook logs)
to
void Committee::RegVoter(RegLogBook& logs)
// again notice the reference ^
Thanks to Lightness Races in Orbit for pointing that out
Remember - to work on the original object, not a copy of it, you should pass it either by a reference or a pointer. By default you should prefer passing by reference, unless you have strong argument to use pointers
I believe the problem is that you return the voter list by-value, meaning that a copy of the voter list is returned:
vector<Voter*> RegLogBook::getVoterList() {
return _voterList;
}
So this line:
logs.getVoterList().push_back(newVoter);
will modify the local copy instead of the value being stored in the object instance.
Try modifying your code to return a reference (by changing the return type to be vector<Voter*>&)
vector<Voter*>& RegLogBook::getVoterList() {
return _voterList;
}
or, maybe better, return a pointer:
vector<Voter*>* RegLogBook::getVoterList() {
return &_voterList;
}
I prefer the last alternative, as this makes it more obvious that the returned value can be modified.
From what I'm seeing your code shouldn't even compile: you're using the new keyword, but you're saving its returned value into a Committee, not into a Committee* as you should. If you are using an overloaded new operator, please post the whole code.

Prevent v8::Local value from being garbage collected

I have a function that stores the value of an argument to an std::vector<v8::Local<v8::Value>> property of a C++ class exposes as an ObjectWrap like this:
NAN_METHOD(MyObject::Write) {
MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.This());
obj->data.push_back(info[0]);
}
However, when I try to read back the value from another C++ function, the value is lost, and becomes undefined.
I'm passing a number to MyObject::Write, and I can confirm info[0]->IsNumber() returns true before pushing it to the vector, however when reading it back, the value it not a number, and in fact returns false for all the types I tested using Is<Type> methods from v8::Value, but still returns true for BooleanValue().
My guess is that the variable is being garbage collected after MyObject::Write returns, however I have no idea how to prevent this from happening.
I'm currently trying to initialise the value as a Persistent value. I tried the following attempts without success:
Nan::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
Nan::Persistent<v8::Value> persistent(info[0]);
Nan::CopyablePersistentTraits::Copy(persistent, p);
And:
v8::Isolate *isolate = info.GetIsolate();
v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> persistent(isolate, info[0]);
But getting tons of C++ errors.
I was running into problems untangling this mess myself. There's a lot of template stuff going on here that we both missed. Here was the solution I found most readable:
// Define the copyable persistent
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
// Create the local value
auto val = v8::Local<v8::Value>::New(
v8::Isolate::GetCurrent(), //< Isolate required
v8::Integer::New(v8::Isolate::GetCurrent(), v) //< Isolate required
);
// Reset() is a TEMPLATE FUNCTION, you have to template it with the same
// template type parameter as the v8::Local you are passing
p.Reset<v8::Value>(v8::Isolate::GetCurrent(), val); //< Isolate required
By "info" I assume you are referring to a v8::FunctionCallbackInfo reference. If so the above code would collapse to the following:
void SomeFunc(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
}
Because the persistent is now copyable you can do things like store it inside a standard library container. This was my use case. This is an example of storing a value in a vector:
std::vector<v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent> vect;
void AccumulateData(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
vect.push_back(p);
}
I hope this helps someone out there.
If you plan on storing v8 values in C++, you need to make them persistent instead of local so they're independent of handle scope and not garbage-collected when the handle scope is released.
Nan has version-independant wrappers for v8::Persistent and Co. Because of using inside std::vector<>, you'll also need to initialize Nan::Persistent with Nan::CopyablePersistentTraits so it becomes copyable (or make an own reference-counted container for it).

luabind: cannot retrieve values from table indexed by non-built-in classes‏

I'm using luabind 0.9.1 from Ryan Pavlik's master distribution with Lua 5.1, cygwin on Win XP SP3 + latest patches x86, boost 1.48, gcc 4.3.4. Lua and boost are cygwin pre-compiled versions.
I've successfully built luabind in both static and shared versions.
Both versions pass all the tests EXCEPT for the test_object_identity.cpp test which fails in both versions.
I've tracked down the problem to the following issue:
If an entry in a table is created for NON built-in class (i.e., not int, string, etc), the value CANNOT be retrieved.
Here's a code piece that demonstrates this:
#include "test.hpp"
#include <luabind/luabind.hpp>
#include <luabind/detail/debug.hpp>
using namespace luabind;
struct test_param
{
int obj;
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def_readwrite("obj", &test_param::obj)
];
test_param temp_object;
object tabc = newtable(L);
tabc[1] = 10;
tabc[temp_object] = 30;
TEST_CHECK( tabc[1] == 10 ); // passes
TEST_CHECK( tabc[temp_object] == 30 ); // FAILS!!!
}
tabc[1] is indeed 10 while tabc[temp_object] is NOT 30! (actually, it seems to be nil)
However, if I use iterate to go over tabc entries, there're the two entries with the CORRECT key/value pairs.
Any ideas?
BTW, overloading the == operator like this:
#include <luabind/operator.hpp>
struct test_param
{
int obj;
bool operator==(test_param const& rhs) const
{
return obj == rhs.obj;
}
};
and
module(L)
[
class_<test_param>("test_param")
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
Doesn't change the result.
I also tried switching to settable() and gettable() from the [] operator. The result is the same. I can see with the debugger that default conversion of the key is invoked, so I guess the error arises from somewhere therein, but it's beyond me to figure out what exactly the problem is.
As the following simple test case show, there're definitely a bug in Luabind's conversion for complex types:
struct test_param : wrap_base
{
int obj;
bool operator==(test_param const& rhs) const
{ return obj == rhs.obj ; }
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def(constructor<>())
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
object tabc, zzk, zzv;
test_param tp, tp1;
tp.obj = 123456;
// create new table
tabc = newtable(L);
// set tabc[tp] = 5;
// o k v
settable( tabc, tp, 5);
// get access to entry through iterator() API
iterator zzi(tabc);
// get the key object
zzk = zzi.key();
// read back the value through gettable() API
// o k
zzv = gettable(tabc, zzk);
// check the entry has the same value
// irrespective of access method
TEST_CHECK ( *zzi == 5 &&
object_cast<int>(zzv) == 5 );
// convert key to its REAL type (test_param)
tp1 = object_cast<test_param>(zzk);
// check two keys are the same
TEST_CHECK( tp == tp1 );
// read the value back from table using REAL key type
zzv = gettable(tabc, tp1);
// check the value
TEST_CHECK( object_cast<int>(zzv) == 5 );
// the previous call FAILS with
// Terminated with exception: "unable to make cast"
// this is because gettable() doesn't return
// a TRUE value, but nil instead
}
Hopefully, someone smarter than me can figure this out,
Thx
I've traced the problem to the fact that Luabind creates a NEW DISTINCT object EVERY time you use a complex value as key (but it does NOT if you use a primitive one or an object).
Here's a small test case that demonstrates this:
struct test_param : wrap_base
{
int obj;
bool operator==(test_param const& rhs) const
{ return obj == rhs.obj ; }
};
void test_main(lua_State* L)
{
using namespace luabind;
module(L)
[
class_<test_param>("test_param")
.def(constructor<>())
.def_readwrite("obj", &test_param::obj)
.def(const_self == const_self)
];
object tabc, zzk, zzv;
test_param tp;
tp.obj = 123456;
tabc = newtable(L);
// o k v
settable( tabc, tp, 5);
iterator zzi(tabc), end;
std::cerr << "value = " << *zzi << "\n";
zzk = zzi.key();
// o k v
settable( tabc, tp, 6);
settable( tabc, zzk, 7);
for (zzi = iterator(tabc); zzi != end; ++zzi)
{
std::cerr << "value = " << *zzi << "\n";
}
}
Notice how tabc[tp] first has the value 5 and then is overwritten with 7 when accessed through the key object. However, when accessed AGAIN through tp, a new entry gets created. This is why gettable() fails subsequently.
Thx,
David
Disclaimer: I'm not an expert on luabind. It's entirely possible I've missed something about luabind's capabilities.
First of all, what is luabind doing when converting test_param to a Lua key? The default policy is copy. To quote the luabind documentation:
This will make a copy of the parameter. This is the default behavior when passing parameters by-value. Note that this can only be used when passing from C++ to Lua. This policy requires that the parameter type has an accessible copy constructor.
In pratice, what this means is that luabind will create a new object (called "full userdata") which is owned by the Lua garbage collector and will copy your struct into it. This is a very safe thing to do because it no longer matters what you do with the c++ object; the Lua object will stick around without really any overhead. This is a good way to do bindings for by-value sorts of objects.
Why does luabind create a new object each time you pass it to Lua? Well, what else could it do? It doesn't matter if the address of the passed object is the same, because the original c++ object could have changed or been destroyed since it was first passed to Lua. (Remember, it was copied to Lua by value, not by reference.) So, with only ==, luabind would have to maintain a list of every object of that type which had ever been passed to Lua (possibly weakly) and compare your object against each one to see if it matches. luabind doesn't do this (nor do I think should it).
Now, let's look at the Lua side. Even though luabind creates two different objects, they're still equal, right? Well, the first problem is that, besides certain built-in types, Lua can only hold objects by reference. Each of those "full userdata" that I mentioned before is actually a pointer. That means that they are not identical.
But they are equal, if we define an __eq meta operation. Unfortunately, Lua itself simply does not support this case. Userdata when used as table keys are always compared by identity, no matter what. This actually isn't special for userdata; it is also true for tables. (Note that to properly support this case, Lua would need to override the hashcode operation on the object in addition to __eq. Lua also does not support overriding the hashcode operation.) I can't speak for the authors of Lua why they did not allow this (and it has been suggested before), but there it is.
So, what are the options?
The simplest thing would be to convert test_param to an object once (explicitly), and then use that object to index the table both times. However, I suspect that while this fixes your toy example, it isn't very helpful in practice.
Another option is simply not to use such types as keys. Actually, I think this is a very good suggestion, since this kind of light-weight binding is quite useful, and the only other option is to discard it.
It looks like you can define a custom conversion on your type. In your example, it might be reasonable to convert your type to a Lua number which will behave well as a table index.
Use a different kind of binding. There will be some overhead, but if you want identity, you'll have to live with it. It sounds like luabind has some support for wrappers, which you may need to use to preserve identity:
When a pointer or reference to a registered class with a wrapper is passed to Lua, luabind will query for it's dynamic type. If the dynamic type inherits from wrap_base, object identity is preserved.