Passing information between SWIG in and freearg typemaps - c++

I have a typemap targetting Python which accepts both an already wrapped pointer object or additionally allows passing a Python sequence. In the case of a wrapped pointer, I do not want to delete the memory as SWIG owns it. However, when processing a sequence I'm allocating a temporary object that needs to be deleted. So I added a flag to my 'in' typemap to mark whether I allocated the pointer target or not. How can I access this flag in the corresponding 'freearg' typemap?
The typemaps look like this:
%typemap(in) name* (void* argp = 0, int res = 0, bool needsDelete = false) {
res = SWIG_ConvertPtr($input, &argp, $descriptor, $disown | 0);
if (SWIG_IsOK(res)) {
$1 = ($ltype)(argp); // already a wrapped pointer, accept
} else {
if (!PySequence_Check($input)) {
SWIG_exception(SWIG_ArgError(res), "Expecting a sequence.");
} else if (PyObject_Length($input) != size) {
SWIG_exception(SWIG_ArgError(res), "Expecting a sequence of length " #size);
} else {
needsDelete = true;
$1 = new name;
for (int i = 0; i < size; ++i) {
PyObject* o = PySequence_GetItem($input, i);
(*$1)[i] = swig::as<type>(o);
Py_DECREF(o);
}
}
}
}
%typemap(freearg) name* {
if ($1 /* && needsDelete */) delete $1;
}
This leads to code being generated that looks like:
{
res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_MyName_t, 0 | 0);
if (SWIG_IsOK(res2)) {
arg2 = (MyName *)(argp2); // already a wrapper pointer, accept
} else {
if (!PySequence_Check(obj1)) {
SWIG_exception(SWIG_ArgError(res2), "Expecting a sequence.");
} else if (PyObject_Length(obj1) != 3) {
SWIG_exception(SWIG_ArgError(res2), "Expecting a sequence of length ""3");
} else {
needsDelete2 = true;
arg2 = new MyName;
for (int i = 0; i < 3; ++i) {
PyObject* o = PySequence_GetItem(obj1, i);
(*arg2)[i] = swig::as<double>(o);
Py_DECREF(o);
}
}
}
}
if (arg1) (arg1)->someMember = *arg2;
resultobj = SWIG_Py_Void();
{
if (arg2 /* && needsDelete */) delete arg2;
}

According to 11.15 Passing data between typemaps from the SWIG manual:
You just need to use the variable as needsDelete$argnum in the freearg typemap.

Related

Print a string from a pointer to its member class

So I'm trying to print a string, but I get no output. However the other values in the class prints just fine.
In main I have a for loop that prints the the values for the Skill class. In Skill I have a pointer to the Ability class.
class Skill {
private:
Ability* ability;
public:
Ability* GetAbility() {
return ability;
};
}
It gets assigned in the constructor like this:
Skill::Skill(Ability* ability){
this->ability = ability;
}
The Ability class contains just a Name and a score.
class Ability {
private:
string name;
float score;
public:
Ability(string name, float score) {
this->name = name;
this->score = score;
};
string Name() { return name; }
float GetScore() { return score; }
};
Now in main I create a few skills and assign an ability to it. as is a container class that initializes a few ablities in a vector and I can get an ability based on its name.
Skill s* = new Skill[2]
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
And then we print
cout << s[i].GetAbility()->Name() << " " << s[i].GetAbility()->GetScore();
However the only output I get is the score. No name what so ever and I can't figure it out. I've tried a few things, but still noting is printing. I'm sure I'm missing something simple that will make me facepalm, but in my defense I haven't written C++ in over 10 years. Thanks in advance.
EDIT: as.GetAbility looks like this:
Ability AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
return Ability();
}
abilityScores is a vector
Your AbilityScores::GetAbility() method is returning an Ability object by value, which means it returns a copy of the source Ability, and so your Skill objects will end up holding dangling pointers to temporary Ability objects that have been destroyed immediately after the Skill constructor exits. So your code has undefined behavior.
AbilityScores::GetAbility() needs to return the Ability object by reference instead:
Ability& AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
throw ...; // there is nothing to return!
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
If you want to return a default Ability when the abilityName is not found, consider using std::map instead of std::vector:
private:
std::map<std::string, Ability> abilityScores;
AbilityScores::AbilityScores() {
abilityScores["Strength"] = Ability("Strength", ...);
abilityScores["Charisma"] = Ability("Charisma", ...);
...
}
Ability& AbilityScores::GetAbility(string abilityName) {
// if you don't mind Name() returning "" for unknown abilities...
return abilityScores[abilityName];
// otherwise...
auto iter = abilityScores.find(abilityName);
if (iter == abilityScores.end()) {
iter = abilityScores.emplace(abilityName, 0.0f).first;
}
return iter->second;
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
Otherwise, return the Ability object by pointer instead:
Ability* AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return &abilityScores[i];
}
}
return nullptr;
// or:
abilityScores.emplace_back(abilityName, 0.0f);
return &(abilityScores.back());
}
...
Skill s* = new Skill[2];
s[0] = Skill(as.GetAbility("Strength"));
s[1] = Skill(as.GetAbility("Charisma"));
...

Creating a second instance of an object changes whole class behavior (C++)

I have written an Arduino library in C++ that contains an iterator class. If I iterate through it using the same instance all the time, it works as expected. If I create a second instance to do so, it will double the amount of stored objects.
WayPointStack wps = *(new WayPointStack());
wps.AddWP(1, 20);
wps.AddWP(2, 420);
WPCommand c1 = wps.GetNextWP(); // Stack length: 2, correct
c1 = wps.GetNextWP(); //
WPCommand c1 = wps.GetNextWP(); // Stack length: 4, not correct
WPCommand c2 = wps.GetNextWP(); //
WPCommand WayPointStack::GetNextWP()
{
Serial.println("Pointer = ");
Serial.println(pointer);
Serial.println("Length = ");
Serial.println(_length);
if (pointer < _length){
pointer++;
return _wp[pointer-1];
}
return *(new WPCommand(_END, 10000));
}
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length] = *(new WPCommand(target, time));
_length++;
}
WayPointStack::WayPointStack()
{
_wp = new WPCommand[arrSize];
_length = 0;
pointer = 0;
}
WPCommand::WPCommand(int target, int time)
{
_target = target;
_time = time;
}
Can someone explain this to me?
WayPointStack wps = *(new WayPointStack());
must be
WayPointStack wps;
because it is enough and that removes the memory leak
In
WPCommand WayPointStack::GetNextWP()
{
...
return *(new WPCommand(_END, 10000));
}
you create an other memory leak, may be do not return the element but its address allowing you to return nullptr on error ?
/*const ?*/ WPCommand * WayPointStack::GetNextWP()
{
Serial.println("Pointer = ");
Serial.println(pointer);
Serial.println("Length = ");
Serial.println(_length);
if (pointer < _length){
return &_wp[pointer++];
}
return nullptr;
}
else use a static var :
WPCommand WayPointStack::GetNextWP()
{
...
static WPCommand error(_END, 10000);
return error;
}
In
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length] = *(new WPCommand(target, time));
_length++;
}
you create an other memory leak, you just need to initialize the entry :
void WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return;
_wp[_length]._target = target, time));
_wp[_length]._time = time;
_length++;
}
you do not signal the error when you cannot add a new element, what about to return a bool valuing false on error and true when you can add :
bool WayPointStack::AddWP(int target, int time)
{
if (_length == arrSize)
return false;
_wp[_length]._target = target;
_wp[_length]._time = time;
_length++;
return true;
}
Finally Why do you not use a std::vector for _wp
It looks like you have a memory leak on this line:
return *(new WPCommand(_END, 10000));
It looks like you are creating WPCommand on heap, then throw away pointer and return a copy !!!
The example is not minimal and complete so it is hard to give better pointers.

Extending python3, how does the garbage collection work

I'm making my own PriorityQueue in C as a python module. I read the basics of python ownership and reference system, so I thought I'd do the following:
In push(): Accept an priority(int) and an object to be saved. Increment the reference count on the object to be saved, since we will be keeping that.
In pop(): Delete the object from my priorityqueue, but don't decrement the reference counter, since that might destroy the object. Instead I transfer my reference ownership to the python function calling my function.
This seemed to work at first hand. But when actually using it in an application I get the following error:
Fatal Python error: GC object already tracked
What does this mean? The stacktrace is not useful at all, it's all inside python files I don't recognize(sre_parse and apport_python_hook).
Just for clarity, these are my C push and pop functions:
(self->heap[index]->key is the priority of the element at that index
self->heap[index]->value is the object)
PyObject* pop(CDSHeap *self) {
//If there aare no elements
if (self->heap[0].value == 0 || self->end == 0) {
Py_RETURN_NONE;
}
//If there is only one element
if (self->end == 1) {
PyObject* result = self->heap[0].value;
self->heap[0].key = 0;
self->end = 0;
return result;
}
//Two or more elements:
//First save the result:
PyObject* result = self->heap[0].value;
//Get the last element, and place it at the top
while (self->heap[self->end].value == 0) self->end--;
self->heap[0].value = self->heap[self->end].value;
self->heap[0].key = self->heap[self->end].key;
self->heap[self->end].value = 0;
//Reheapify the heap
int ptr = 0;
while (self->end >= ptr) {
if (self->heap[ptr*2+1].value != 0 && self->heap[ptr*2+1].key < self->heap[ptr].key
&& (self->heap[ptr*2+2].value == 0 || self->heap[ptr*2+1].key <= self->heap[ptr*2+2].key)) {
swapElement(self->heap, ptr, ptr*2+1);
ptr = ptr*2+1;
}else
if (self->heap[ptr*2+2].value != 0 && self->heap[ptr*2+2].value < self->heap[ptr].value) {
swapElement(self->heap, ptr, ptr*2+2);
ptr = ptr*2+2;
} else {
break;
}
}
return result;
}
PyObject* push(CDSHeap *self, PyObject* args) {
int k;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO",&k, &obj)){
return NULL;
}
Py_INCREF(obj);
//Add the element to the end of the heap
self->heap[self->end].key = k;
self->heap[self->end].value = obj;
//Increment the size and reheapify
int ptr = self->end++;
while (ptr > 0) {
int parent = (ptr-1)/2;
if (self->heap[ptr].key < self->heap[parent].key) {
swapElement(self->heap, ptr, parent);
ptr = parent;
} else {
Py_RETURN_NONE;
}
}
Py_RETURN_NONE;
}

Invalid Pointer Passed By Address-of(&) Operator

Alright, so I'm practicing with C++ classes and pointers. When suddenly...
If I try to get the address of my object passed in the parameters, it gives me an invalid address.
What is going on here?
P.S You can ignore the if statement, it shouldn't be relevant to this particular problem.
Picture of the Problem
.
int ChainLinkz::chainCount = 0;
ChainLinkz::ChainLinkz(int i) {
data = i;
chainID = chainCount++;
fLink = this;
addr = this;
nLink = 0;
printf("Created Link with Value: %i Addr: %x.\n", data, this);
}
ChainLinkz *ChainLinkz::next() {
if (nLink)
return nLink;
else
return 0;
}
ChainLinkz *ChainLinkz::last() {
ChainLinkz * lastLink = fLink;
while (lastLink->next()) {
lastLink = lastLink->next();
}
return lastLink;
}
ChainLinkz ChainLinkz::addLink(ChainLinkz link) {
if (link.nLink) {
if (&link == link.fLink) { // Replace fLink with new address in all instances of previous chain | Fix the old chain
ChainLinkz *t_link = link.nLink;
while (t_link->next()) {
t_link = t_link->next();
t_link->fLink = link.nLink;
}
} else { // Replace nLink for previous link | Fix the old chain
ChainLinkz *t_link = link.fLink;
while (t_link != &link)
t_link = t_link->next();
t_link->nLink = link.next();
}
}
last()->nLink = link.addr;
printf("\n&link: %x | Real Addr: %x \n\n", (ChainLinkz*)&link, link.addr);
link.nLink = 0; //Update values to new chain
link.fLink = fLink;
return link;
}
ChainLinkz ChainLinkz::addLink(ChainLinkz *link) {
printf("Overloader: %x.\n", link);
return addLink(*link);
}
ChainLinkz ChainLinkz::operator>>(ChainLinkz link) {
return addLink(link);
}
ChainLinkz ChainLinkz::operator>>(ChainLinkz *link) {
printf("Overloader: %x.\n", link);
return addLink(*link);
}
Solved the problem by using references instead of passing the object itself.
ChainLinkz ChainLinkz::addLink(ChainLinkz &link) {
printf("Overloaded New: %p\n", &link);
return addLink(&link);
}
ChainLinkz ChainLinkz::addLink(ChainLinkz *link) {
if (link->nLink) {
if (link == link->fLink) { // Replace fLink with new address in all instances of previous chain | Fix the old chain
ChainLinkz *t_link = link->nLink;
while (t_link->next()) {
t_link = t_link->next();
t_link->fLink = link->nLink;
}
}
else { // Replace nLink for previous link | Fix the old chain
ChainLinkz *t_link = link->fLink;
while (t_link != link)
t_link = t_link->next();
t_link->nLink = link->next();
}
}
last()->nLink = link;
link->nLink = 0; //Update values to new chain
link->fLink = fLink;
return *link;
}
ChainLinkz ChainLinkz::operator>>(ChainLinkz &link) {
return addLink(&link);
}
ChainLinkz ChainLinkz::operator>>(ChainLinkz *link) {
printf("Overloaded: %p.\n", link);
return addLink(link);
}

Dangling memory/ unallocated memory issue

I've this piece of code, which is called by a timer Update mechanism.
However, I notice, that the memory size of the application, while running, continuously increases by 4, indicating that there might be a rogue pointer, or some other issue.
void RtdbConnection::getItemList()
{
std::vector<CString> tagList = mItemList->getItems();
//CString str(_T("STD-DOL1"));
PwItemList* pil = mPwSrv->GetItemList();
CPwItem pw ;
for(auto it = tagList.begin(); it != tagList.end(); ++it)
{
pw = mPwSrv->GetItem(*it);
pil->AddItem(&(PwItem)pw);
}
pil->AddInfo(DB_DESC); //Description
pil->AddInfo(DB_QALRM); // Alarm Status
pil->AddInfo(DB_QUNAK); //UNACK status
pil->AddInfo(DB_AL_PRI); // Priority of the alarm tag
pil->ExecuteQuery();
int i = 0;
for (auto it = tagList.begin(); i < pil->GetInfoRetrievedCount() && it != tagList.end(); i+=4, it++)
{
//item = {0};
CString str(*it);
PwInfo info = pil->GetInfo(i);
CString p(info.szValue().c_str());
bool isAlarm = pil->GetInfo(i+1).bValue();
bool isAck = pil->GetInfo(i+2).bValue();
int priority = pil->GetInfo(i+3).iValue();
item = ItemInfo(str, p, isAlarm, isAck, priority);
//int r = sizeof(item);
mItemList->setInfo(str, item); // Set the details for the item of the List
}
delete pil;
pil = NULL;
}
I cannot seem to find a memory block requiring de-allocation here. Nor is there any allocation of memory when I step inside the following function :
mItemList->setInfo(str, item);
which is defined as :
void ItemList::setInfo(CString tagname, ItemInfo info)
{
int flag = 0;
COLORREF tempColour;
std::map<CString, ItemInfo>::iterator tempIterator;
if ( (tempIterator = mAlarmListMap.find(tagname)) !=mAlarmListMap.end() )
{
//remove the current iteminfo and insert new one
if(mAlarmListMap[tagname].getPriority() != info.getPriority() && (mAlarmListMap[tagname].getPriority()!=0))
{
mAlarmListMap[tagname].updatePriority(info.getPriority());
mAlarmListMap[tagname].mPrioChanged = TRUE;
}
else
{
mAlarmListMap[tagname].mPrioChanged = FALSE;
((mAlarmListMap[tagname].getPrevPriority() != 0)?(mAlarmListMap[tagname].ResetPrevPriority()):TRUE);
mAlarmListMap[tagname].setPriority(info.getPriority());
}
mAlarmListMap[tagname].setDescription(info.getDescription());
mAlarmListMap[tagname].setAlarm(info.getAlarmStat());
mAlarmListMap[tagname].setAlarmAck(info.getAckStat());
tempColour = mColourLogic->setUpdatedColour(mAlarmListMap[tagname].getAlarmStat(), mAlarmListMap[tagname].getAckStat(), flag);
mAlarmListMap[tagname].setColour(tempColour);
if(!(info.getAlarmStat() || info.getAckStat()))
{
flag = 1;
mAlarmListMap[tagname].mIsRTN = true;
mAlarmListMap[tagname].setDisplayCondition(false);
}
else
{
mAlarmListMap[tagname].setDisplayCondition(true);
}
//((mAlarmListMap[tagname].mIsRTN == true)?
}
else
{
tempIterator = mAlarmListMap.begin();
tempColour = mColourLogic->fillColourFirst(info.getAlarmStat(), info.getAckStat());
info.setColour(tempColour);
mAlarmListMap.insert(tempIterator, std::pair<CString,ItemInfo>(tagname,info));
}
}
I tried juggling with the allocations, but the increase is always a constant 4.
Could anyone kindly look and highlight where the issue could be?
Thanks a lot.