C++ passing class to constructor = not passing same instance? - c++

It seems that, when I pass an class it is not passing a persistant (the same) instance of that class as I would expect. I'm assuming this has something to do with memory state but I would appreciate it if someone could explain exactly what is happening. The issue is easily demonstrated as follows :
Main.ino
#include "Debug.h"
#include "Box.h"
Debug debug;
Box box(debug);
void loop(){
debug.message("loop");
debug.line();
}
void setup(){
debug.init();
box.init();
debug.message("Setup Complete");
debug.line();
}
Debug.h
#ifndef DEBUG_H
#define DEBUG_H
class Debug {
private:
bool state;
public:
Debug();
void init();
void message(const char *str);
void message(int);
void line();
};
#endif
Debug.cpp
#include "Debug.h"
#include <Arduino.h>
Debug::Debug() : state(false) {}
void Debug::init() {
if (state == false){
Serial.begin(9600);
state = true;
}
}
void Debug::message(const char *messageChar) {
if (state){
const char *p;
p = messageChar;
while (*p) {
Serial.print(*p);
p++;
}
}
}
void Debug::message(int messageInt) {
if (state){
Serial.print(messageInt);
}
}
void Debug::line() {
if (state){
Serial.println();
}
}
Box.h
#ifndef BOX_H
#define BOX_H
#include "Debug.h"
class Box {
private:
Debug debug;
public:
Box(Debug &debug);
void init();
};
#endif
Box.cpp
#include "Box.h"
#include <Arduino.h>
Box::Box(Debug &debug):
debug(debug)
{}
void Box::init(){
// Switches
pinMode(28, INPUT_PULLUP);
debug.message("Box intialized");
debug.line();
}
So the above code outputs to serial:
Setup Complete
If I modify Box::init() to
void Box::init(){
// Switches
pinMode(28, INPUT_PULLUP);
debug.init();
debug.message("Box intialized");
debug.line();
}
I get what I want :
Box initialized
Setup Complete
If I get rid of Box constructor class and instead do
void Box::init(Debug &debug){
this->debug = debug;
// Switches
pinMode(28, INPUT_PULLUP);
debug.message("Box intialized");
debug.line();
}
Called via Main.ino like
void setup(){
debug.init();
box.init(debug);
debug.message("Setup Complete");
debug.line();
}
I get the desired response again. I don't understand why my first attempt doesn't work nor do I feel comfortable knowing what best practices are. I would appreciate any guidance.

You have two Debug values in your code. One global, one member of the Box class.
Those are two distinct values, since Box create or copy from a value to create its own, and there's the global one.
A solution would be to contain a reference or a pointer.
Here's the example with a reference:
class Box {
private:
Debug& debug;
// ^---- there
public:
Box(Debug &debug);
void init();
};
If you want Box to still be assignable, then use a pointer:
class Box {
private:
Debug* debug;
// ^---- now it's a star
public:
Box(Debug &debug);
void init();
};
Box::Box(Debug &debug):
debug(&debug)
{} // ^----- here, we take the address of the debug variable.
Since references are immutable, you loose some important feature of the language: assignment.
struct thing {
int& ref;
};
int main () {
int a, b;
thing t1{a}, t2{b};
t1 = t2; // ERROR!
}
The assignment would cause t1.ref to point to b after the assignment.
Pointer has a more difficult syntax and hard to guess semantics. However, they play very well with assignment since they give you more freedom:
struct thing {
int* ptr;
};
int main () {
int a, b;
thing t1{&a}, t2{&b};
t1 = t2; // Works, t1.ptr points to b
}

Related

Why this function variable only works if it's static?

I'm trying to put a bunch of sounds in a std::vector because it's very convenient.
I'm using an auxiliary variable called laser, load the sound into it and, if it's everything ok, push_back into the vector.
When I try to play any the sound, nothing happens, not even error messages which should be printed if anything goes wrong.
Just for curiosity I made laser static and voilá, it works flawlessly (or it seems to).
I'd like to know why.
Header file:
// audio_system.h
#ifndef KUGE_HEADERS_AUDIO_SYSTEM_H_
#define KUGE_HEADERS_AUDIO_SYSTEM_H_
#include "event.h"
#include "system.h"
#include "../sdl2_wrappers/sdl2_wrappers.h"
#include "../include/resources_path.h"
#include <vector>
namespace kuge {
class AudioSystem : virtual public System {
public:
AudioSystem(EventBus& bus): System(bus) {}
void handleEvent(const Event& event);
static bool loadResources();
private:
static void generateRandomSequence();
static std::vector<ktp::SDL2_Sound> lasers_;
};
} // end namespace kuge
#endif // KUGE_HEADERS_AUDIO_SYSTEM_H_
cpp file:
#include "event_bus.h"
#include "audio_system.h"
std::vector<ktp::SDL2_Sound> kuge::AudioSystem::lasers_{};
void kuge::AudioSystem::generateRandomSequence() {}
void kuge::AudioSystem::handleEvent(const Event& event) {
switch (event.getType()) {
case EventTypes::LaserFired:
if (lasers_[0].play() == -1) {
ktp::logSDLError("laser_.play");
}
break;
default:
break;
}
}
bool kuge::AudioSystem::loadResources() {
static ktp::SDL2_Sound laser{}; // here! If I don't make this static, nothing happens
if (!laser.loadSound(ktp::getResourcesPath() + "sounds/laser2.wav")) {
return false;
} else {
lasers_.push_back(laser);
}
ktp::logMessage("AudioSystem: resources loaded.");
return true;
}
OK, so following the advices from the comments, I've made the following changes to make ktp::SDL2_Sound class follow the rule of 0 and now it works without the need to set the laser variable to static. This solves the problem, but I'm still not sure why it worked being static.
class SDL2_Sound {
public:
//~SDL2_Sound() { free(); } // now I don't need any destructor
bool loadSound(const std::string& path);
int play(int loops = 0);
private:
void free();
// Mix_Chunk* sound_ = nullptr; // old raw pointer
std::shared_ptr<Mix_Chunk> sound_{};
};
/* void ktp::SDL2_Sound::free() {
if (sound_ != nullptr) {
Mix_FreeChunk(sound_);
sound_ = nullptr;
}
} */
bool ktp::SDL2_Sound::loadSound(const std::string& path) {
//free();
sound_.reset(Mix_LoadWAV(path.c_str()), &Mix_FreeChunk);
//sound_ = Mix_LoadWAV(path.c_str());
if (sound_ == nullptr) {
ktp::logSDLError("Mix_LoadWAV", path);
return false;
}
return true;
}

Crash: When accessing vector from class

I'm programming an ESP32 UI and have run into this issue:
I have a class Menu, and define a vector _menuItemStack in its header.
I create an Object MenuItem from outside and pass it to the function addMenuItem(MenuItem menuItem). It adds it to the stack. Which works, when I declare the vector in the Menu.cpp it runs. But it won't be unique for each object, I think it becomes static?
So I declared the vector as private in the header, while it will compile. it crashes immediately.
What is my mistake? C++ makes my head hurt.
Menu.h
/*
Menu.h - Menu Class
*/
#ifndef Menu_h
#define Menu_h
#include "Arduino.h"
#include "StackArray.h"
#include "MenuItem.h"
#include "SPI.h"
#include "U8g2lib.h"
class Menu
{
public:
Menu();
void update();
void draw();
void addMenuItem(MenuItem menuItem);
private:
int arrayPos;
std::vector<MenuItem> _menuItemStack;
};
#endif
Menu.cpp
#include "Menu.h"
extern U8G2_SSD1327_MIDAS_128X128_2_4W_HW_SPI u8g2;
Menu::Menu() {
arrayPos = 0;
}
void Menu::draw() {
u8g2.setFont(u8g2_font_6x10_tf);
int posY = 0;
for (MenuItem &m : _menuItemStack){
u8g2.drawStr(0,posY+15,m.getText().c_str());
posY+=15;
}
}
void Menu::update() {
}
void Menu::addMenuItem(MenuItem menuItem){
arrayPos++;
_menuItemStack.push_back(menuItem);
//debug
Serial.println(arrayPos);
Serial.println(menuItem.getText());
}
Notes: the std::stdlib is included higher up.
EDIT:
MenuItem.cpp
#include "MenuItem.h"
extern U8G2_SSD1327_MIDAS_128X128_2_4W_HW_SPI u8g2;
MenuItem::MenuItem() {
_text = new String;
}
MenuItem::MenuItem(const MenuItem &obj){
_text = new String;
*_text = *obj._text;
}
void MenuItem::draw(){
}
void MenuItem::update(){
}
void MenuItem::setText(String txt){
*_text = txt;
}
String MenuItem::getText(){
return *_text;
}
void MenuItem::attachHandler(CallbackFunction f){
callback = f;
}
void MenuItem::run(){
if (callback != NULL) callback();
}
MenuItem.h
#ifndef MenuItem_h
#define MenuItem_h
#include "Arduino.h"
#include "StackArray.h"
#include "SPI.h"
#include "U8g2lib.h"
class MenuItem
{
private:
typedef void (*CallbackFunction)();
CallbackFunction callback = NULL;
String *_text;
public:
MenuItem();
MenuItem(const MenuItem &obj);
void draw();
void update();
void run();
void setText(String txt);
void attachHandler(CallbackFunction f);
String getText();
};
#endif
The menuItem passed into the addMenuItem function is a copy that has a lifespan until the end of that function.
Try passing in the menu item as a reference so that your list of menu items will be populated with objects that have a lifespan longer than the addMenuItem function. That change the signature to look like this:
void Menu::addMenuItem(MenuItem& menuItem)
When you call std::vector::push_back you create a copy of your object and store it into the vector. So first check, the copy constructor of your class and if the error could be caused by this.
Then you need to know where is stored the memory necessary for std::vector.
On embedded target you may not be using the traditional standard library and manipulating memory can be tricky.
When you declare your vector as a global variable, it is highly probable that the memory required is not in the same zone than when you declare it as a private member of a class. This will depend on your platform, compiler, linker script, and the lib C++ your are using. std::vector use an allocator, on Linux you can get away without looking at what it does, when on embedded target you need to know which allocator your are using and where the memory is.
You can try to print the address of std::vector::data() to check that. Then you will probably have to either provide your own allocator or to reserve a portion of memory large enough to hold the vector and initialize the data contained in your vector at this memory address.

Float prints a large, weird value

So, I create a State class. In that State class's create function, it creates a StateVisual class by calling the StateVisual class's create function, passing itself as a parameter. (The parameter is a reference so that there is no copying). The StateVisual then sets the parameter (The State Instance), as it's parent variable, which is a pointer of a State type.
In the StateVisual's create function, everything works fine. However, when you get to it's update method, and try to print it's parent size, it prints some weird value.
#ifndef STATE_H
#define STATE_H
#include "cocos2d.h"
class StateVisual;
class State {
public:
State();
~State();
static State create();
StateVisual *visual;
float size;
void setSize(float);
void update(float);
private:
cocos2d::Scheduler* _scheduler;
};
#endif
StateVisual.cpp
#ifndef STATE_VIS_H
#define STATE_VIS_H
#include "cocos2d.h"
#include "State.h"
class StateVisual : public cocos2d::Sprite {
public:
StateVisual();
~StateVisual();
// create a visual
State* parent;
static StateVisual* create(State& parent);
cocos2d::Label* label;
void setSize(float);
void update(float);
private:
bool _activated;
float _size;
};
#endif
State.cpp
#include "State.h"
#include "GameScene.h"
State::State() : size(0) {
CCLOG("Created");
}
State::~State() {
}
void State::setSize(float newSize) {
size = newSize;
CCLOG("%f, %f", newSize, size);
}
void State::update(float dt) {
}
State State::create() {
State state;
state.visual = StateVisual::create(state);
cocos2d::SEL_SCHEDULE ss;
return state;
}
StateVisual.cpp
#include "StateVisual.h"
#include "GameScene.h"
using namespace cocos2d;
StateVisual::StateVisual() : parent(nullptr) {
CCLOG("New STATE VISUAL!");
}
StateVisual::~StateVisual() {
}
void StateVisual::setSize(float size) {
setContentSize(Size(size, size));
if (size > 30) {
label->setSystemFontSize(size*.1);
label->setOpacity(255);
}
else {
label->setOpacity(0);
}
}
void StateVisual::update(float dt) {
cocos2d::MathUtil::smooth(&_size, parent->size, dt, .2);
setSize(_size);
CCLOG("%f, %f", _size, (*this->parent).size);
}
StateVisual* StateVisual::create(State &parent) {
StateVisual* visual(new StateVisual());
if (visual->initWithFile("Circle.png"))
{
visual->setSize(200);
visual->_size = 200;
visual->parent = &parent;
visual->parent->setSize(20);
CCLOG("PARENT SIZE: %f", visual->parent->size);
visual->autorelease();
visual->scheduleUpdate();
return visual;
}
CC_SAFE_DELETE(visual);
return NULL;
}
It outputs:
Created
New STATE VISUAL!
cocos2d: fullPathForFilename: No file found at /cc_2x2_white_image. Possible
missing file.
20.000000, 20.000000
PARENT SIZE: 20.000000
500.000000, 500.000000
cocos2d: QuadCommand: resizing index size from [-1] to [2560]
168.058044, -107374176.000000 <-- Those are the weird values it prints
155.130508, -107374176.000000
The program '[1464] State.exe' has exited with code 0 (0x0).
0xCCCCCCCC, a typical value used to fill uninitialized memory in Debug builds, interpreted as a 32-bit float, equals -107374176.000000. You're printing an uninitialized float value.
State State::create() {
State state;
state.visual = StateVisual::create(state);
cocos2d::SEL_SCHEDULE ss;
return state;
}
At the end of this function the local object state is destroyed a copy ois made (or moved to a new object). Which means any pointer to the address &state is invalid after the end of State::create
visual->parent = &parent; // parent = state object on stack
Because of this line visual->parent is now dangling.
Those weird values are the random content of you thread stack...
What you should do is use shared pointers for state\parent.
void StateVisual::update(float dt) {
cocos2d::MathUtil::smooth(&_size, parent->size, dt, .2);
setSize(_size);
CCLOG("%f, %f", _size, (*this->parent).size);
Why do you use parent->size in 1 row of function and (*this->parent).size in third?
Why don't you use getters and setters?
Why haven't you shown header files?
Why haven't you prepared minimal example (like just parent-child logic and sizes without labels, positions etc.?
What is this suposed to do? StateVisual* visual(new StateVisual());
If visual is automatic variable, i think it should look loke StateVisual visual(new StateVisual()); otherwise shouldn't it be StateVisual* visual = new StateVisual(new StateVisual()); Also are you sure you want to pass new StateVisual object into constructor of StateVisual?

Objects Accessing Variables of Container Class - C++

How can an object access a variable belonging the class containing it?
Right now I have a class called system that contains some other objects, and those objects need to access and modify one of the variables in the System class.
Example:
Class System {
BlockA _blockA = new BlockA();
BlockB _blockB = new BlockB();
BlockC _blockC = new BlockC();
BlockD _blockD = new BlockD();
int myVariable;
...stuff...
}
Class BlockA {
...stuff...
void someFunction () {
System.myVariable++;
}
...stuff...
}
etc...
Alright so I thought about this some more and realized that when initializing the objects, I will pass a pointer to the variable of interest. That way all objects can read that variable. For anyone else with this problem, if you need to write, you'll have to make sure that the variable is atomic.
Hard to know exactly what you're after, but appears something along these lines:
#BlockA.h
#ifndef BLOCKA_H
#define BLOCKA_H
class System;
class BlockA {
System* sys;
public:
BlockA(System* sys) : sys(sys) {}
void SomeFunction();
};
#endif // BLOCKA_H
#BlockA.cpp
#include "System.h"
void BlockA::SomeFunction() {
sys->setMyVariable(sys->getMyVariable() + 1);
}
#System.h
#ifndef SYSTEM_H
#define SYSTEM_H
class BlockA;
class System {
BlockA* _blockA;
int myVariable;
public:
System();
int getMyVariable() const;
void setMyVariable(int value);
BlockA& getBlockA() const;
};
#endif // SYSTEM_H
#System.cpp
#include "System.h"
#include "BlockA.h"
System::System()
: _blockA(new BlockA(this)) { }
int System::getMyVariable() const {
return myVariable;
}
void System::setMyVariable(int value) {
myVariable = value;
}
BlockA& System::getBlockA() const {
return *_blockA;
}

Function calls with class members?

Before I present the code which is found at the bottom of this post I would like to talk about the issue and the fix's that I do not desire. Okay basically I've created a GUI from scratch sort of and one requirement I wanted for this was allow components to have their own click executions so if i click a button or tab etc.. It would call Component->Execute(); Well normally you would do something like a switch statement of ids and if that components ID equaled n number then it would perform this action. Well that seemed kinda dumb to me and I thought there has to be a better way. I eventually tried to incorporate a feature in JAVA where you would do like Component.AddActionListener(new ActionListener( public void execute(ActionEvent ae) { })); or something like that and I thought that this feature has to be possible in C++. I eventually came across storing void functions into a variable in which could be executed at any time and modified at any time. However I hadn't noticed an issue and that was this only worked with static functions. So below you'll see my problem. I've patched the problem by using a pointer to SomeClass however this would mean having an individual function call for every class type is there no way to store a function callback to a non-static class member without doing the below strategy? and instead doing a strategy like the commented out code?
//Main.cpp
#include <iostream> //system requires this.
#include "SomeClass.h"
void DoSomething1(void)
{
std::cout << "We Called Static DoSomething1\n";
}
void DoSomething2(void)
{
std::cout << "We Called Static DoSomething2\n";
}
int main()
{
void (*function_call2)(SomeClass*);
void (*function_call)() = DoSomething1; //This works No Problems!
function_call(); //Will Call the DoSomething1(void);
function_call = DoSomething2; //This works No Problems!
function_call(); //Will Call the DoSomething2(void);
SomeClass *some = new SomeClass(); //Create a SomeClass pointer;
function_call = SomeClass::DoSomething3; //Static SomeClass::DoSomething3();
function_call(); //Will Call the SomeClass::DoSomething3(void);
//function_call = some->DoSomething4; //Non-Static SomeClass::DoSomething4 gives an error.
//function_call(); //Not used because of error above.
function_call2 = SomeClass::DoSomething5; //Store the SomeClass::DoSomething(SomeClass* some);
function_call2(some); //Call out SomeClass::DoSomething5 which calls on SomeClass::DoSomething4's non static member.
system("pause");
return 0;
}
//SomeClass.hpp
#pragma once
#include <iostream>
class SomeClass
{
public:
SomeClass();
~SomeClass();
public:
static void DoSomething3(void);
void DoSomething4(void);
static void DoSomething5(SomeClass* some);
};
//SomeClass.cpp
#include "SomeClass.h"
SomeClass::SomeClass(void)
{
}
SomeClass::~SomeClass(void)
{
}
void SomeClass::DoSomething3(void)
{
std::cout << "We Called Static DoSomething3\n";
}
void SomeClass::DoSomething4(void)
{
std::cout << "We Called Non-Static DoSomething4\n";
}
void SomeClass::DoSomething5(SomeClass *some)
{
some->DoSomething4();
}
Secondary Fix for what I'll do not an exact answer I wanted but it meets my needs for now along with allowing additional features which would have become overly complicate had this not existed.
//Component.hpp
#pragma once
#include <iostream>
#include <windows.h>
#include <d3dx9.h>
#include <d3d9.h>
#include "Constants.hpp"
#include "ScreenState.hpp"
#include "ComponentType.hpp"
using namespace std;
class Component
{
static void EMPTY(void) { }
static void EMPTY(int i) { }
public:
Component(void)
{
callback = EMPTY;
callback2 = EMPTY;
callback_id = -1;
}
Component* SetFunction(void (*callback)())
{
this->callback = callback;
return this;
}
Component* SetFunction(void (*callback2)(int), int id)
{
this->callback_id = id;
this->callback2 = callback2;
return this;
}
void execute(void)
{
callback();
callback2(callback_id);
}
}
The syntax for pointers-to-member-functions is as follows:
struct Foo
{
void bar(int, int);
void zip(int, int);
};
Foo x;
void (Foo::*p)(int, int) = &Foo::bar; // pointer
(x.*p)(1, 2); // invocation
p = &Foo::zip;
(x.*p)(3, 4); // invocation
Mind the additional parentheses in the function invocation, which is needed to get the correct operator precedence. The member-dereference operator is .* (and there's also ->* from an instance pointer).