Can you use different constants for class objects in C++? - c++

I came across a class which sole purpose was to create blinking leds. He used the class for 2 objects which had a different blinking interval. I started thinking in how I could use constants but nothing came to me.
Is it possible to use a const int in combination with the constructor to use different constants for objects?
I am aware that a const int is to be initialized at the same place where it is declared, so I'd guess that the answer is 'no'
If not, are there workarounds to achieve the same thing? That is using different constants (so less memory usage) for different objects of the same type.
The used platform in question is the arduino IDE and an atmega328P.
May it perhaps be that the compiler recognizes that the variables are actually used as constants and treat them as such?
.h
class BlinkingLed
{
private:
int blPin;
short blinkInterval; // <-- the contant
bool blinking;
bool ledOn;
long lastTime;
public:
BlinkingLed(int, int);
void setBlinkInterval(int); // never used, should not exist
int getBlinkInterval(); // never used, should not exist
void setLedOn(bool);
bool getLedOn();
void attachPin();
void heartBeat();
};
.cpp
BlinkingLed::BlinkingLed(int aPin, int aBlinkInterval) // constructor
{
blPin = aPin;
blinking = false;
ledOn = false;
blinkInterval = aBlinkInterval; // <-- the contant
}
The objects are made with this line. The aki class needs 2 BlinkingLed objects.
AKI aki(new BlinkingLed(23,333), new BlinkingLed(22,667), 24); // Red blinks 90/minute, green 45/minute
This is the constructor of aki:
AKI::AKI(BlinkingLed *aRedLight, BlinkingLed *aGreenLight, int aBellPin)
{
redLight = aRedLight;
greenLight = aGreenLight;
bellPin = aBellPin;
}
The 333 and 367 are stored in variables and I want these to become constants to preserve memory space. How do I do that?

To summarize the discussion, and correct some of your wrong assumptions:
class BlinkingLed {
private:
const byte blPin; // This should definitely be const
const unsigned short blinkInterval; // <-- the desired constant (why?)
bool blinking;
bool ledOn;
unsigned long lastTime;
public:
BlinkingLed(byte pin, unsigned short interval)
: blPin(pin), blinkInterval(interval) {}
// void setBlinkInterval(int); // impossible for a const Interval
void init() {pinMode(blPin, OUTPUT);} // should not be done in a c'tor
void run(); // to be called as often as possible for a smooth heartbeat
unsigned short getBlinkInterval() {return blinkInterval;} // why not
void setLed(bool); // stops blinking
bool isLedOn();
void heartBeat(); // start blinking
};
BTW: data type int usually blames you for not thinking about it. :)

Related

Qualified name is not allowed in C++, already compiling in C++ 17 [duplicate]

This question already has answers here:
C++ Qualified name is not allowed in member declaration
(3 answers)
Closed 1 year ago.
I'm trying to follow the Zombie Arena project in Beginning C++ Game Programming by John Horton.
However, Pickup.h is giving me problems.
class Pickup
{
private:
//Start value for health pickups
const int HEALTH_START_VALUE = 50;
const int AMMO_START_VALUE = 12;
const int START_WAIT_TIME = 10;
const int START_SECONDS_TO_LIVE = 5;
// The sprite that represents this pickup
Sprite m_Sprite;
// The arena it exists in
IntRect m_Arena;
// How much is this pickup worth?
int m_Value;
// What type of pickup is this?
// 1 = health, 2 = ammo
int m_Type;
// Handle spawning and disappearing
bool m_Spawned;
float m_SecondsSinceSpawn;
float m_SecondsSinceDeSpawn;
float m_SecondsToLive;
float m_SecondsToWait;
// Public prototypes go here
public:
Pickup::Pickup(int type);
// Prepare a new pickup
void setArena(IntRect arena);
void spawn();
// Check the position of a pickup
FloatRect getPosition();
// Get the sprite for drawing
Sprite getSprite();
// Let the pickup update itself each frame
void update(float elapsedTime);
// Is this pickup currently spawned?
bool isSpawned();
// Get the goodness from the pickup
int gotIt();
// Upgrade the value of each pickup
void upgrade();
};
When I try to compile the program, I get an illegal qualified name in member declaration error from Pickup::Pickup(int type). What could be wrong? I've tried to debug this with no success. Please help. I'm already compiling in C++ 17.
Instead of this declaration of the constructor
Pickup::Pickup(int type);
write
Pickup(int type);
The qualified name of the constructor declaration is not correct though as far as I know some compilers like MS VS allow such declarations.
You may use a qualified name of a member function in its definition outside the class definition.

error when erasing object in vector. how do i add move assignment operators to my classes?

I am getting an error when I am trying to erase an object from my vector
googled but I can't understand what's wrong. from what I gathered I am calling the erase function correctly but I have to provide a move assignment operator to my classes?
my function where i call the erase
void removegroup(const short &group){
switch (tracker[group].group){
case 0: {
guardvec.erase(guardvec.begin()+tracker[group].position); //this is the problem it compiles just fine if i comment out this line
//guardvec.erase(remove(guardvec.begin(), guardvec.end(), tracker[group].position),guardvec.end()); //tried this and it doesnt work
}
break;
}
for (short counter=0;counter<tracker.size();counter++)
if ((tracker[counter].group==tracker[group].group)&&(tracker[counter].position>tracker[group].position))
tracker[counter].position=tracker[counter].position--;
}
my class
class guardhitdice {
friend class guard;
short const times = 2, dice = 8, plus = 2;
};
class guard : private guardhitdice {
private:
short units, XP, morale, totalHP=0, dead=0, wounded=0;
short* HP = new short[units];
public:
void showstats(){
std::cout << "STR=1, DEX=1, CON=1, INT=0, WIS=0, CHA=0, Perception=2, Passive Perception=12"<<std::endl
<<"current xp: "<<XP<<"total HP across units: "<<totalHP<<"casualties: "<<dead<<"wounded: "<<wounded;
}
void initializeHP(){
for (short counter=0; counter<units-1; counter++){
HP[counter]=plus + D(times, dice);
totalHP+=HP[counter];
}
}
guard(const short &xp, short &Units, short &Morale){
XP=xp;
units=Units;
morale=Morale;
// short* HP = new short[units];
initializeHP();
}
~guard(){
delete HP;
}
};
here is my compiler error https://pastebin.com/KSniFkVD
it should be able to remove the object at tracker[group].position. btw position is a short
i also tried adding this to my classes but they don't work
guardhitdice& guardhitdice ::operator=(guardhitdice&&);
guard& guard ::operator=(guard&&);
it works if I do it for normal vectors but not for vectors of objects
Your problem can be reduced down to
#include <vector>
class test{
short const times = 2;
};
int main()
{
std::vector<test> t;
t.push_back(test{});
t.erase(t.begin()); //<-- BAM!
}
Example: https://ideone.com/MlwUyI
vector does a lot of copy-and-assigning. Copying is cool, but test contains a const member. You can't change a const variable, so you can't assign it.
But since it's initialized with a literal and there's no constructor that'll allow the value to be initialized to something else, all instances of test will have the same value. That's a pretty good fit for static. static variables don't take part in assignment, so the default assignment operator is usable.
class test{
static short const times = 2;
};
Example: https://ideone.com/npUi4B

C++ Vector read access violation Mylast returned 0x8

I really need help on this one cause I am extremely stuck and have no idea what to do.
Edit:
A lot of you guys are saying that I need to use the debugger but let me be clear I have not used C++ for an extremely long time and I've used visual studio for a grand total of 2 weeks so I do not know all the cool stuff it can do with the debugger.
I am a student at university at the beginning of my second year who is trying to work out how to do something mostly by failing.
I AM NOT a professional coder and I don't have all the knowledge that you people have when it comes to these issues and that is why I am asking this question. I am trying my best to show my issue so yes my code contains a lot of errors as I only have a very basic understanding of a lot of C++ principles so can you please keep that in mind when commenting
I'm only posting this here because I can don't know who else to ask right now.
I have a function called world that is suppose to call my render class to draw all the objects inside of its vector to the screen.
#include "C_World.h"
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
C_World::~C_World()
{
delete[] render;
}
// adds an object to the world vector
void C_World::addToWorld(C_renderable* a)
{
world_list.push_back(a);
}
void C_World::World_Update()
{
render->ClearScreen();
World_Render();
}
void C_World::World_Render() {
for (int i = 0; i < 1; i++)
{
//render->DrawSprite(world_list[i]->getTexture(), world_list[i]->get_X, world_list[i]->get_Y());
render->DrawSprite(1, 1, 1);
}
}
While testing I commented out the Sprites get functions in order to check if they were causing the issue.
the renderer sprites are added to the vector list in the constructor through the create sprite function
C_Renderer::C_Renderer()
{
// test sprite: Id = 1
CreateSprite("WhiteBlock.png", 250, 250, 1);
}
I thought this might of been the issue so I had it in other functions but this didn't solve anything
Here are the Draw and create Sprite functions
// Creates a sprite that is stored in the SpriteList
// Sprites in the spriteList can be used in the drawSprite function
void C_Renderer::CreateSprite(std::string texture_name,
unsigned int Texture_Width, unsigned int Texture_height, int spriteId)
{
C_Sprite *a = new C_Sprite(texture_name,Texture_Width,
Texture_height,spriteId);
SpriteList.push_back(a);
size_t b = SpriteList.size();
HAPI.DebugText(std::to_string(b));
}
// Draws a sprite to the X and Y co-ordinates
void C_Renderer::DrawSprite(int id,int x,int y)
{
Blit(screen, _screenWidth, SpriteList[id]->get_Texture(),
SpriteList[id]->getTexture_W(), SpriteList[id]->getTexture_H(), x, y);
}
I even added some test code into the create sprite function to check to see if the sprite was being added too the vector list. It returns 1 so I assume it is.
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<C_Sprite *,
std::allocator<C_Sprite *> > >::_Mylast(...) returned 0x8.
that is the full error that I get from the compiler
I'm really really stuck if there is anymore information you need just say and ill post it straight away
Edit 2:
#pragma once
#include <HAPI_lib.h>
#include <vector>
#include <iostream>
#include "C_renderable.h"
#include "C_Renderer.h"
class C_World
{
public:
C_World();
~C_World();
C_Renderer *render = nullptr;
void World_Update();
void addToWorld(C_renderable* a);
private:
std::vector<C_renderable*> world_list;
void C_World::World_Render();
};
#pragma once
#include <HAPI_lib.h>
#include "C_renderable.h"
#include "C_Sprite.h"
#include <vector>
class C_Renderer
{
public:
C_Renderer();
~C_Renderer();
// gets a pointer to the top left of screen
BYTE *screen = HAPI.GetScreenPointer();
void Blit(BYTE *destination, unsigned int destWidth,
BYTE *source, unsigned int sourceWidth, unsigned int sourceHeight,
int posX, int posY);
void C_Renderer::BlitBackground(BYTE *destination,
unsigned int destWidth, unsigned int destHeight, BYTE *source,
unsigned int sourceWidth, unsigned int sourceHeight);
void SetPixel(unsigned int x,
unsigned int y, HAPI_TColour col,BYTE *screen, unsigned int width);
unsigned int _screenWidth = 1750;
void CreateSprite(std::string texture_name,
unsigned int Texture_Width,unsigned int Texture_height, int spriteId);
void DrawSprite(int id, int x, int y);
void ClearScreen();
private:
std::vector<C_Sprite*> SpriteList;
};
I don't say this lightly, but the code you've shown is absolutely terrible. You need to stop and go back several levels in your understanding of C++.
In all likeliness, your crash is the result of a simple "shadowing" issue in one or more of your functions:
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
C_World::~C_World()
{
delete[] render;
}
There are multiple things wrong here, and you don't show the definition of C_World but if this code compiles we can deduce that it has a member render, and you have fallen into a common trap.
C_Renderer *render = new C_Renderer;
Because this line starts with a type this is a definition of a new, local variable, render. Your compiler should be warning you that this shadows the class-scope variable of the same name.
What these lines of code
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
do is:
. assign an undefined value to `this->render`,
. create a *local* variable `render`,
. construct a dynamic `C_Renderer` presumably on the heap,
. assign that to the *local* variable `render`,
. exit the function discarding the value of `render`.
So at this point the memory is no-longer being tracked, it has been leaked, and this->render is pointing to an undefined value.
You repeat this problem in several of your functions, assigning new results to local variables and doing nothing with them. It may not be this specific instance of the issue that's causing the problem.
Your next problem is a mismatch of new/delete vs new[]/delete[]:
C_World::~C_World()
{
delete[] render;
}
this would result in undefined behavior: this->render is undefined, and delete[] on a non-new[] allocation is undefined.
Most programmers use a naming convention that distinguishes a member variable from a local variable. Two common practices are an m_ prefix or an _ suffix for members, e.g.
class C_World
{
public:
C_Foo* m_foo; // option a
C_Renderer* render_; // option b
// ...
}
Perhaps you should consider using modern C++'s concept of smart pointers:
#include <memory>
class C_World {
// ...
std::unique_ptr<C_Renderer> render_;
// ...
};
C_World::C_World()
: render_(new C_Renderer) // initializer list
{}
But it's unclear why you are using a dynamic allocation here in the first place. It seems like an instance member would be better:
class C_World {
C_Renderer render_;
};
C_World::C_World() : render_() {}

C++ Member variable losing value after constructor

I'm having a problem in one of my classes. I have these 2 classes, GameApp and Simulation:
GameApp.h
#pragma once
#include "Simulation.h"
class Simulation;
class GameApp {
static GameApp *instance;
public:
~GameApp(void);
static GameApp *initializeContext(const char *gameTitle, const int windowWidth, const int windowHeight);
//void setSimulation(Simulation &simulation) { *(this->simulation) = simulation; }
Simulation *getSimulation() { return simulation; }
static const int TARGET_FPS = 50; // Frames per second
private:
GameApp(void);
Simulation *simulation;
double frameIntervalList[TARGET_FPS]; // A list containing the time to render the last 60 frames
// Other stuff that doesn't matter
Simulation.h
#pragma once
#include <vector>
#include "GameApp.h"
class Simulation {
public:
Simulation(void);
Simulation(const Simulation &copy);
~Simulation(void);
Simulation &operator=(const Simulation &other);
protected:
std::vector<Entity*> *entities;
And, in GameApp.cpp, in the function initializeContext, I have:
#include "GameApp.h"
GameApp *GameApp::instance = NULL;
GameApp::GameApp() {
gamePaused = false;
frameIntervalSum = 0;
this->simulation = new Simulation();
for (int i = 0; i < 60; i++) {
frameIntervalList[i] = 0;
}
}
GameApp *GameApp::initializeContext(const char *gameTitle, const int windowWidth, const int windowHeight) {
instance = new GameApp();
// (...) Rest of initialize funcion
}
The problem is, for some misterious reason, when I call initializeContext, the first line of it calls GameApp's constructor, which creates a new Simulation, which allocates correctly and I get a memory address for the simulation pointer. But when the program exits the constructor of GameApp, in the line right after instance = new GameApp();, if I check the simulator variable on the newly created instance using the debugger, I get the pointer value of 0x00000000, and the Simulation that I just created is gone. This would indeed happen if I was using the stack memory on the constructor, but I'm clearly using new, creating the new Simulation variable in the correct way, I guess. What may be happening here?
Also, there's a commented setSimulation function on the GameApp.h file. When I leave this uncommented, I get the compiler error 2582, "operator= function is unavailable in Simulation". Can this be related to my problem?
EDIT: The problem was indeed the for loop with the hardcoded size. I changed the size of frameIntervalList from 60 to 50 in the header but forgot to change it on the loop. Also updated code to show the declaration of frameIntervalList.
The only code that executes between the initialization of the simulation member variable and the code that comes after the GameApp ctor is the for loop that initialzes frameIntervalList so its initialization with a hardcoded size might overwrite the value of simulation variable if you are unlucky. (Or lucky because it helps you to catch a very ugly bug early!!! :-)

std::string constructor corrupts pointer

I have an Entity class, which contains 3 pointers: m_rigidBody, m_entity, and m_parent. Somewhere in Entity::setModel(std::string model), it's crashing. Apparently, this is caused by bad data in m_entity. The weird thing is that I nulled it in the constructor and haven't touched it since then. I debugged it and put a watchpoint on it, and it comes up that the m_entity member is being changed in the constructor for std::string that's being called while converting a const char* into an std::string for the setModel call. I'm running on a Mac, if that helps (I think I remember some problem with std::string on the Mac). Any ideas about what's going on?
EDIT: Here's the code for GEntity:
GEntity::GEntity(GWorld* world, unsigned long int idNum) {
GEntity(world, idNum, btTransform::getIdentity());
}
GEntity::GEntity(GWorld* world, unsigned long int idNum, btTransform trans) : m_id(idNum), m_trans(trans), m_world(world) {
// Init unused properties
m_rigidBody = NULL;
m_entity = NULL; // I'm setting it here
m_parent = NULL;
// Find internal object name
std::ostringstream ss;
ss << "Entity" << idNum << "InWorld" << world;
m_name = ss.str();
// Create a scene node
m_sceneNode = m_world->m_sceneMgr->getRootSceneNode()->createChildSceneNode(m_name+"Node");
// Initialize the SceneNode's transformation
m_sceneNode->setPosition(bv3toOv3(m_trans.getOrigin()));
m_sceneNode->setOrientation(bqToOq(m_trans.getRotation()));
}
void GEntity::setModel(std::string model) {
m_model = model;
// Delete entity on model change
if(m_entity != NULL) { // And by the time this line comes around, it's corrupt
m_world->m_sceneMgr->destroyEntity(m_entity);
m_entity = NULL;
}
// Create new entity with given model
m_entity = m_world->m_sceneMgr->createEntity(m_name+"Ent", model);
// Apply a new rigid body if needed
if(m_rigidBody != NULL) {
initPhysics();
}
}
void GEntity::initPhysics() {
deinitPhysics();
}
void GEntity::deinitPhysics() {
if(m_rigidBody != NULL) {
m_world->m_dynWorld->removeRigidBody(m_rigidBody);
delete m_rigidBody;
m_rigidBody = NULL;
}
}
And here's the definition of GEntity:
class GEntity : public btMotionState {
public:
GEntity(GWorld* world, unsigned long int idNum);
GEntity(GWorld* world, unsigned long int idNum, btTransform trans);
void setModel(std::string modelName);
void initPhysics();
void deinitPhysics();
void getWorldTransform(btTransform& worldTrans) const;
void setWorldTransform(const btTransform &trans);
void parent(GEntity* parent);
protected:
unsigned long int m_id;
// Physics representation
btTransform m_trans;
btRigidBody* m_rigidBody;
// Graphics representation
Ogre::SceneNode* m_sceneNode;
Ogre::Entity* m_entity;
// Engine representation
GWorld* m_world;
GEntity* m_parent;
std::string m_name;
std::string m_model; // Used to find physics collision mesh
};
And here's the code calling setModel:
// Setup game world
GWorld* world = new GWorld(win);
GEntity* ent = world->createEntity();
ent->setModel(std::string("Cube.mesh"));
Your problem is that this line is constructing a nameless temporary GEntity inside the constructor body for a different GEntity. The temporary is then thrown away once the statement completes and no further initialization of the non-temporary GEntity is performed.
GEntity(world, idNum, btTransform::getIdentity());
If you want to share some initialization code between your two constructors you should create a member function that performs the required actions and call this function from both constructors. C++ doesn't (currently) allow you to delegate initialization from one constructor to a different constructor or call two constructors on the same object.
My best guess is that the problem is in GWorld::createEntity. If you're creating a local GEntity on the stack and returning a pointer to it, you'll see something like what you describe, as the GEntity is destroyed when GWorld::createEntity returns and the memory is reused for the temp string constructed to pass to setModel
Edit
I see you've added more code, including the definition of createEntity. That looks fine, but I would still suggest looking for some way in which the GEntity you're seeing the problem with gets deleted (and the memory reused for a string) before you call setModel.
One solution I have found is to use string.resize(n), which will resize the function. However, I do not know why this works, and I feel my problem is with my code since std::string is part of the standard C++ library.
I can't find the answer but I can make a suggestion that will help catch the problem:
Add assertions. A lot of assertions. Each one of those functions really need some assertions at least at their beginning. That will certainly help you catch wrong states early.
And by the way, you should use a constant reference as parameter of your setModel() function.
In C++ you can not call a constructor from within a constructor.
Try
GEntity::GEntity(GWorld* world, unsigned long int idNum) : GEntity(world, idNum, btTransform::getIdentity() {}