Arduino: undefined reference to `Class::attribute' - c++

I am developing a library Button to handle some functions of buttons and a class ButtonManager handling the query of the states of those buttons. I don't want to have to create an object for the ButtonManager class so I figured I had to use the static keyword for every attribute and method. In addition I am using a third party library to handle timer interrupts which needs a static function as a parameter.
When I try to compile my code, I get the undefined reference to 'ButtonManager::head' error.
My ButtonManager.h looks like this:
#ifndef BUTTON_MANAGER_H
#define BUTTON_MANAGER_H
#include <Arduino.h>
#include "Button.h"
#include "TimerOne.h"
struct ButtonListItem {
Button* button;
ButtonListItem* next;
};
class ButtonManager {
public:
static ButtonListItem* head = NULL;
static void begin();
static void addButton(Button* newButton);
static void handleButtons();
};
#endif
And the ButtonManager.cpp file looks like this:
#include "ButtonManager.h"
void ButtonManager::begin() {
Timer1.initialize(100000);
Timer1.attachInterrupt(ButtonManager::handleButtons); // handleButtons every 0.1 seconds
}
void ButtonManager::addButton(Button *newButton) {
ButtonListItem* link = new ButtonListItem;
link->button = newButton;
link->next = ButtonManager::head;
ButtonManager::head = link;
}
void ButtonManager::handleButtons() {
ButtonListItem* buttonPtr = ButtonManager::head;
while (buttonPtr != NULL) {
buttonPtr->button->handleButton();
buttonPtr = buttonPtr->next;
}
}
I really don't get what is wrong about this implementation. Is it even the right approach?
I'd appreciate any help and tips how to improve my code.

static ButtonListItem* head = NULL;
If you want to use static data members you must also define them. Declaration of such a member is not a definition.
Put this line at the top of your .cpp file (below #include):
ButtonListItem* ButtonManager::head = NULL;
You may need to also remove = NULL from the declaration in the header. Initialization should be done with the definition.
As for other things you should provide some way to clear the list of buttons. Currently there is no way to de-allocate memory allocated with:
ButtonListItem* link = new ButtonListItem;
(and possibly also memory occupied by the Buttons themselves if no other party is to own that memory). Whenever you use new there should be corresponding delete. And even though for your application it may not matter (static head lives till the end of the execution) this is a good practice to apply proper de-allocation always.

Related

How can I properly initialize C++ objects within an Arduino program?

In my simple Arduino project, in order to keep things tidy, I decided to create a "Mode Manager" that will handle passing between one mode and another. The basic concept is that each time I want to change the mode, then it will instantiate the next mode and replace the previous one.
Please note that I have 12+ years experience in OOP and Java / Scala, but no experience whatsoever in C++, just the stuff needed to make an Arduino do its stuff without too many structures.
With some studying I managed to create the following "interface" structure:
File: modes/ModeManager.h. This should keep a reference to the current mode, and delegate to it the looping and instantiating the next mode (each mode will know which is the next in line)
#ifndef __MODE_MANAGER__
#define __MODE_MANAGER__
#include <stdint.h>
#include "modes/Mode.h"
class ModeManager {
private:
Mode *mode;
public:
ModeManager();
~ModeManager() {};
virtual void loop(uint8_t voltage);
};
#endif
File: modes/Mode.h is the actual "mode" that runs the real loop function of the program. It also handles instantiating the next mode
#ifndef __MODE__
#define __MODE__
#include <stdint.h>
class Mode {
public:
Mode() {}
virtual ~Mode() {}
virtual void loop(uint8_t voltage) = 0;
virtual void getNext(Mode * target) = 0;
};
#endif
File: modes/ModeManager.cpp
#include "ModeManager.h"
#include <stdint.h>
#include <Arduino.h>
#include "modes/Mode.h"
#include "modes/DummyMode.h"
#define VOLTAGE_NEXT_MODE 5
ModeManager::ModeManager() {
DummyMode cmode = DummyMode();
mode = & cmode; // I'm not sure how this should actually be done
}
void ModeManager::loop(uint8_t voltage) {
if (voltage == VOLTAGE_NEXT_MODE) {
Serial.println("Switching to next mode");
mode->getNext(mode);
} else {
Serial.println("Calling mode loop");
mode->loop(voltage); // From here, nothing.
}
}
File: modes/DummyMode.h
#ifndef __DUMMY_MODE__
#define __DUMMY_MODE__
#include "modes/Mode.h"
class DummyMode : public Mode {
public:
DummyMode();
~DummyMode() {}
virtual void loop(uint8_t voltage);
virtual void getNext(Mode * target);
};
#endif
File: modes/DummyMode.cpp
#include "modes/DummyMode.h"
#include <Arduino.h>
DummyMode::DummyMode() {
Serial.println("Initialization of dummy mode");
}
void DummyMode::loop(uint8_t voltage) {
Serial.print("Voltage: ");
Serial.println(voltage);
}
void DummyMode::getNext(Mode * target) {
DummyMode nextMode = DummyMode();
target = &nextMode;
}
and finally my main.cpp
#include <Arduino.h>
#include "modes/ModeManager.h"
#include "modules/memory.h"
#include "modules/monitor.h"
ModeManager * modeManager;
void setup() {
pinMode(A0, INPUT);
Serial.begin(9600);
Serial.println("Init");
ModeManager mm = ModeManager();
modeManager = & mm;
}
void loop(void) {
uint8_t voltage = map(analogRead(A0), 0, 1024, 0, 5);
modeManager->loop(voltage);
}
Now, theoretically I see no reason why this should not work. In practice I'm 99.9% sure I am doing something wrong with initializations and pointers.
When I try to run this code, I get the following serial out:
Init
Initialization of dummy mode
Calling mode loop
Which means that it freezes at the first iteration of the loop, right before calling mode->loop(voltage);
Can anyone point me in the right direction? Again, I have really no experience of C++, and my knowledge of how to make this structure came from various online resources of C++ programming, including some answers here so please bear with me
Here:
DummyMode cmode = DummyMode();
you are creating a DummyMode instance cmode with automatic lifetime (commonly referred to as on the stack).
You then take the address and assign that to another variable:
mode = & cmode; // I'm not sure how this should actually be done
Since cmode is an object with automatic lifetime it will be destroyed when the program leaves the scope in which it was created. As a result the pointer stored in mode will be dangling and referring to an object that no longer exists. Dereferencing it will trigger undefined behaviour.
It looks like your intention is to create the object with dynamic lifetime.
You can do that with the following:
mode = new DummyMode();
Though then you are responsible for ensure the object is destroyed when it is no longer needed.
That would be done with delete:
delete mode;
In more idiomatic/modern C++ it is typically to use smart pointers to manage the lifetime of such objects and not manually call delete. I see that C++'s standard library is not available for Arduino, but there does seem to be a smart pointer available: https://www.arduino.cc/reference/en/libraries/arxsmartptr/
I would recommend having a good look at using that to have a much easier time avoiding memory leaks.

C++ nonstatic member reference must be relative to a specific object

First things first, I think it will make more sense to see my code. Header:
#include <vector>
#include "GUIItem.h"
class WindowManager
{
private:
static WindowManager* s_wndmgr; //A singleton maintains a pointer to itself as a class variable
std::vector<GUIItem*> m_guilist; //storage for gui item
//...
public:
static void Create();
static void Destroy();
static inline WindowManager* Get()
{
return s_wndmgr;
}
static void addItem(GUIItem *newGUIItem);
};
And the class:
#include "WindowManager.h"
#include "GUIButton.h"
WindowManager* WindowManager::s_wndmgr = NULL;
WindowManager::WindowManager()
{
s_wndmgr = NULL;
}
WindowManager::~WindowManager()
{
//Cleanup other stuff if necessary
delete s_wndmgr;
}
void WindowManager::Create()
{
if ( !s_wndmgr ) s_wndmgr = new WindowManager();
GUIButton *m_btn1 = new GUIButton();
addItem(m_btn1);
}
void WindowManager::Destroy()
{
if ( s_wndmgr ) delete s_wndmgr;
}
void WindowManager::addItem(GUIItem * newGUIItem)
{
m_guilist.push_back(newGUIItem);
}
Hopefully it makes some kind of sense. I'm trying to create a simple gui framework from scratch in OpenGL and this is a simple window manager. My issue is with m_guilist which should be accessible so that new GUIItems can be added to it such as happens in Create (GUIItem being a base class from which others inherit, such as GUIButton).
In this case I'm using addItem in order to append items to the list but I'm running into the a nonstatic member reference must be relative to a specific object error regarding the line inside addItem. I'm a little confused as to why this is the case. I understand that making addItem static is the reason for this error, but that was done in order for it to be called from within Create. Is there a way around this?
Sorry, this is quite the poor question and my grasp of C++ isn't great yet though I'm getting there. Any thoughts on this? Something tells me I'd be better to leave the Create function alone and create another nonstatic function to create my GUIItems and add them to the list.
addItem is a static function, which does not not operate on any instance of WindowManager. It can not access m_guilist, which is non-static without an instance.
Maybe you just want:
Get()->m_guilist.push_back(newGUIItem);
But you're starting to make the interface static, that's kind of hybrid. It's usually that addItem is non-static and you call it with the instance you acquire by WindowManager::Get().
Yet, WindowManager doesn't have inaccessible or deleted constructor to qualify as a singleton class. Ways to implement a Singleton design pattern.

Inter-Module Functionality List in C++ - is it a bad idea?

In an old game of mine, I reached a point where keeping a header containing all possible code pieces for player "weapons", for lack of better word, forced recompilation of good 30% of the program. (If you are not into games, think about code for brushes and tools in a graphics editor, or buttons on calculator.) Then I decided that I'm not into keeping a list of what program can do, and came up with something more automatic... but it abuses global constructors.
Specifically, I made a class of double-linked list nodes that registered themselves into public class-static scope list of these nodes. Then, whenever I added a functionality of "known kind" into the program, I inserted a file-static scope list node exposing an object describing that functionality to the parts of the program which actually used it (usually a name, some virtual functions, and in some cases private variables). This means that if I want to add a new functionality of that kind to the program, I don't need to recompile any other module; the same if I want to remove it.
When I described this to my colleagues, most found this concept suspect, but I didn't receive any constructive feedback beyond some people suggesting using a non-language mechanism, like an external preprocessor. So... is it a bad practice to use setups like that, assuming you document them? Should I use it in my future programs? Maybe there's a way to explicitly ask linker to generate something like this?
Here's the header code for completeness, though I think you can answer my questions without looking at it. One could add destructor for safety, I guess... and the example usage is trivial of course.
#include <iostream>
using namespace std;
//general header
template <class Content>
struct InterFileListNode {
InterFileListNode * next, * prev;
Content content;
static InterFileListNode * first, * last;
InterFileListNode(const Content & t) : content(t) {
if (last==0) {
first = last = this;
next = prev = 0;
} else {
prev = last;
next = 0;
last->next = this;
last = this;
}
}
};
template <class Content>
InterFileListNode<Content> * InterFileListNode<Content>::first = 0;
template <class Content>
InterFileListNode<Content> * InterFileListNode<Content>::last = 0;
//header for functionality type
struct Functionality {
const char * name;
void (*funcptr)(void);
};
typedef InterFileListNode<Functionality *> FunctionalityNode;
//module with functionality
void nothing() {}
static Functionality foobar = {"do nothing", nothing};
static FunctionalityNode node(&foobar);
//module using functionality (usually a toolbox, but here for simplicity not):
int main() {
FunctionalityNode * ptr = FunctionalityNode::first;
while (ptr != 0) {
cout << ptr->content->name << endl;
(ptr->content->funcptr)();
ptr = ptr->next;
}
}

access wxFrame(s) & wxDialog(s) globally

I'm new to C++ and new to codelite and also new to wxCrafter. I'm trying to build some GUI apps, but I'm messed up about object passthrough in C++. I spent a few hours and I just understand a little bit of that. First, to pass variables between wxFrame/wxDialog, I should create a instance of that class.
in frameA.cpp
void frameA::buttonAClicked() {
frameB * frameB1 = new frameB(NULL);
frameB1->connect(this);
}
in frameB.cpp
void frameB::connect(frameA *upper) {
//now I can access frameA via upper
}
But for a more complex case(e.g. 10 frames), values entered by user need to be shared between frames. I think it's better to make the frames/dialogs to be handle by a parent. Since all classes were triggered by main.cpp, so I think MainApp() will be good idea. So I tried to do this:
main.cpp:
class MainApp : public wxApp {
public:
frameA * frameA1;
frameB * frameB1
//frameC, frameD, frameE etc.
MainApp() {}
virtual ~MainApp() {}
virtual bool OnInit() {
frameA1 = new frameA(NULL);
frameB1 = new frameB(NULL);
frameA1->connect(this);
frameB1->connect(this);
SetTopWindow(frameA);
return GetTopWindow()->Show();
}
};
in both frameA.cpp and frameB.cpp:
frameA::connect(wxApp *par) {
this->parent = par;
}
Now I'm able to access MainApp via parent, but the two member objects(one is itself) was not found. Am I missed something? I'm really new to C++. Is that any better way (or a formal way) to do?
There is convenient way to make kind of global data in wxWidgets application. Create file ApplicationData.h:
#pragma once // replace with #ifndef ... if not supported by your compiler
class frameA;
// place here required forward declarations
// ...
struct ApplicationData
{
frameA* frameA1;
// any other data you need
};
Include this file to application class h-file:
#include "ApplicationData.h"
class MainApp: public wxApp
{
public:
ApplicationData applicationData; // or may it private with get/set functions
...
};
Finally, you can access applicationData from any place of wxWidgets application:
ApplicationData* pData = &wxGetApp().applicationData;
// Set/read global data members here:
// pData->...
See also: wxGetApp function definition in wxWidgets reference: http://docs.wxwidgets.org/2.6/wx_appinifunctions.html Note that you must add IMPLEMENT_APP and DECLARE_APP macros to make it working.

EXC_BAD_ACCESS upon accessing a static member?

I've developed a game on Cocos2d-x v2 platform
I started on Android, after completely finishing the coding on Eclipse I used the same code on Xcode to create and iOS version.
After adding all the required libraries, I succeeded in compiling the code. However, the game hangs the moment it runs on an iOS device, although it runs without any problem on Android.
I tried both the emulator and an iPod, but I always get an EXC_BAD_ACCESS when accessing a static member from a static method. The static member would always point to 0x0!!
Here's an excerpt from the code:\
AppDelegate.cpp
#include "AppDelegate.h"
#include "NASEncData.h"
AppDelegate::AppDelegate()
{
ep = NASEncData::sharedUserData();
}
NASEncData.h
namespace CocosNas
{
class NASEncData : public CCObject
{
public:
static NASEncData* sharedUserData();
private:
NASEncData();
static void initXMLFilePath();
static std::string m_sFilePath;
}
}
NASEncData.cpp
#include "NASEncData.h"
NASEncData* NASEncData::sharedUserData()
{
initXMLFilePath();
// only create xml file one time
// the file exists after the programe exit
if ((! isXMLFileExist()) && (! createXMLFile()))
{
return NULL;
}
if (! m_spUserData)
{
m_spUserData = new NASEncData();
}
return m_spUserData;
}
void NASEncData::initXMLFilePath()
{
if (! m_sbIsFilePathInitialized)
{
m_sFilePath += CCFileUtils::sharedFileUtils()->getWriteablePath() + NASENCDATA_XML_FILE_NAME; <----error happens here
m_sbIsFilePathInitialized = true;
}
}
Based on the comments on your question, your problem could be the initialization order of static data. To be more specific, I think it is possible that the static AppDelegate instance gets created and initialized before the static members in the NASEncData. And this problem could also explain the fact that you are seeing different behavior on different platform, because the initialization order of unrelated static data are compiler and linker dependent.
To fix this, you could change your NASEncData like this: (note that this is only one possible fix, although if the initialization order of statics is really your problem, I think this is the simplest and best solution, apart from redesigning your code so that you don't have to rely on static members.)
NASEncData.h
namespace CocosNas
{
class NASEncData : public CCObject
{
public:
static NASEncData* sharedUserData();
private:
NASEncData();
static void initXMLFilePath();
// Note how the stuff below this line have changed
struct StaticData
{
std::string m_sFilePath;
// Put other static members here
// (e.g. m_sbIsFilePathInitialized, m_spUserData, etc.)
// Put a proper constructor here if needed
};
static StaticData & getStaticData ()
{
static StaticData s_data;
return s_data;
}
}
}
NASEncData.cpp
void NASEncData::initXMLFilePath()
{
if (! m_sbIsFilePathInitialized)
{
// Note the change in accessing m_sFilePath
// You should access all your static members like this
getStaticData().m_sFilePath +=
CCFileUtils::sharedFileUtils()->getWriteablePath() +
NASENCDATA_XML_FILE_NAME;
getStaticData().m_sbIsFilePathInitialized = true;
}
}
What this does in ensure that when you try and access your static member data, they have already been initialized. This happens because all your static member data are now defined inside a function as static, and for accessing them you have to call that function, and the compiler generates code to make sure that the first time that function is invoked (and only the first time) your data is constructed and initialized properly, which in turn means that the first time you actually try to access this data, whenever and wherever that may be from, your data is properly initialized.
It was indeed an initialization problem I just had to move the code from the construction to bool AppDelegate::applicationDidFinishLaunching() and it worked!