Passing an array of objects to a function is not giving back the desired values set in the settingUp function.
Try to print the values stored in the first item of the array in the main function.
main.ccp:
//** Libraries included **//
using namespace std;
//#include "common.h"
#include "settingUp.h"
int main(){
statusClass status[5];
//** Main Functions **//
settingUp(status);
status[1].printValues();
}
settings.h:
#ifndef settingUp_h
#define settingUp_h
//** Libraries **//
#include "statusClass.h"
#include <stdio.h>
#include "dataClass.h"
void settingUp(statusClass *_status);
#endif
settings.ccp //UPDATE: few lines corrected!
//** Libraries **//
#include "settingUp.h"
//** Status classes and their functions **//
void settingUp(statusClass *_status){
//statusClass statusProv;
dataClass * prueba0 = new dataClass(); //Corrected!
dataClass * prueba1 = new dataClass(); //Corrected!
dataClass * prueba2 = new dataClass(); //Corrected!
const dataClass * arrayPrueba[3];
prueba0.setValues(1);
prueba1.setValues(2);
prueba2.setValues(3);
arrayPrueba[0] = prueba0; //Corrected!
arrayPrueba[1] = prueba1; //Corrected!
arrayPrueba[2] = prueba2; //Corrected!
_status[1].setValues(1, arrayPrueba);
//_status = &statusProv;
_status[0].printValues();
}
UPDATE:
statusClass.cpp:
//** Libraries **//
#include "statusClass.h"
//** Status classes and their functions **//
void statusClass::setValues (uint8_t _statusSelectorByte, const dataClass **_array){
newStatusSelectorByte = _statusSelectorByte;
array = _array;
};
void statusClass::printValues(){
printf("TP: statusClass -> printValues: Prueba = %d\n", newStatusSelectorByte);
printf("TP: statusClass -> printValues: arrayPrueba = %d\n", array[1]->length);
}
printValues() in the settingUp() gives the right values, not in main.cpp.
Update: for array[0]->length works, for array[2]->length does not work.
When you do the following:
dataClass prueba0;
you create an object on the stack. This object is valid until you exit that function.
One solution is to allocate that object:
dataClass * prueba0 = new dataClass();
That means at some point you'll need to delete the object with:
delete prueba0;
To avoid having to use delete, you should look into using shared pointers.
I think your next problem is that in main you have:
statusClass status[5];
So 5 different status objects.
Then inside the initialization function, you specifically initialize _status[1]:
_status[1].setValues(1, arrayPrueba);
In other words, your _status[0] access within the initialization is going to show the random values that were on the stack when entering main() (which by luck are zeroes by default).
Maybe you are thinking that:
array = _array;
copies the values from one array to another. Right now, all that does is save a pointer. The array on the left is the pointer you created named arrayPrueba.
I just don't think you understand your code much and to tell you the truth, you should be using std::vector instead of C arrays. If you really want to write C++ code, learn the standard library (STL).
Related
Hopefully my title isn't too confusing. I'm trying to write a sound manager for my game using SFML. I'm trying to replace my new/delete with the "smart pointer" std::shared_ptr. This is what I have so far.
/* SoundManager.h */
#ifndef SOUNDMANAGER_H
#define SOUNDMANAGER_H
#include <SFML/Audio.hpp>
#include <string>
#include <memory>
class SoundManager
{
public:
~SoundManager();
struct jteSound
{
sf::Sound snd;
sf::SoundBuffer sndBuffer;
std::string name;
};
//Load a new sound from path and store it in audio bank bnk.
//Banks are simply std::vectors of type jteSound.
void registerNewSound(std::vector<std::shared_ptr<jteSound>> &bnk, std::string path, std::string sndName);
//Footsteps bank
std::vector<std::shared_ptr<jteSound>> bnkFootsteps;
};
#endif // SOUNDMANAGER_H
/* SoundManager.cpp */
#include "SoundManager.h"
#include <stdlib.h>
SoundManager::~SoundManager()
{
/*
//Cleanup each sound bank that we use.
for (std::vector<jteSound*>::iterator it = bnkFootsteps.begin(); it != bnkFootsteps.end(); ++it) {
delete *it;
}
*/
}
void SoundManager::registerNewSound(std::vector<std::shared_ptr<jteSound>> &bnk, std::string path, std::string sndName)
{
static int counter = 0;
for (int i = counter; counter <i+1; counter++) {
bnk.push_back(jteSound);
bnk[i]->name = sndName;
bnk[i]->sndBuffer.loadFromFile(path);
bnk[i]->snd.setBuffer(bnk[i]->sndBuffer);
}
}
bnk.push_back(jteSound); gives me a compiler error. If I remove the line, the program compiles, but crashes. I have tried things like emplace_back() or jteSound* or new jteSound, but nothing works. I always get a lengthy compiler error or immediate runtime crash. When I use regular pointers and new/delete, see https://bpaste.net/show/fa684f2f2d5e and https://bpaste.net/show/c74ac701ce7a, the code works as expected. Any thoughts appreciated!
The type of the elements inside your std::vector is std::shared_ptr<jteSound> which means that std::vector::push_back will accept only instances of that type.
To make your code work you have two options. The first is using std::make_shared helper function as follows:
bnk.push_back(std::make_shared<jteSound>());
// the equivalent counterpart is:
bnk.push_back(std::shared_ptr<jteSound>(new jteSound));
The second is using std::vector::emplace as follows:
bnk.emplace(bnk.end(), new jteSound);
As the comments below warn, using the second option is risky because it can cause memory leak when the new jteSound succeeds but the std::vector::emplace has to reallocate memory and fails.
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_() {}
I'm having a tough time creating a an array that holds objects of a class I made. I cannot use std::vector to hold the objects so here is what I tried to do:
This is my cpp file:
Resistor.cpp:
#include "Resistor.h"
Resistor::Resistor(int rIndex_, string name_, double resistance_){
int rIndex = rIndex_;
name = name_;
resistance = resistance_;
}
I'm trying to make an array of these Resistor objects in another cpp file:
Rparser.cpp:
#include "Resistor.h"
#include "Node.h"
#include "Rparser.h"
Rparser::Rparser(int maxNodes_, int maxResistors_){
maxNodes = maxNodes_;
maxResistors = maxResistors_;
resistorArray = new Resistor[maxResistors_]; //trying to make an array
}
My Rparser.h file looks like this, as you can see I declared a pointer that points to Resistor datatype:
#include "Resistor.h"
#include "Node.h"
class Rparser{
public:
int maxNodes;
int maxResistors;
Resistor *resistorArray; //declared a pointer here
Rparser(int maxNodes_, int maxResistors_);
~Rparser(){};
I'm getting the following errors:
error: no matching function for call to ‘Resistor::Resistor()’
note: candidates are: Resistor::Resistor(int, std::string, double, int*)
note: Resistor::Resistor(const Resistor&)
Why is it treating the line resistorArray = new Resistor[maxResistors]
as a function call instead of creating an array?
You need a Resistor constructor that takes no arguments (that is what the compiler is telling you in the error message, it is not a function call, but a call to the no arguments constructor.). Think about it, new Resistor[] specifies no constructor arguments.
After changing my source output to a pointer, I started getting segfaults happening on calls to my GetOutput() function. I'm fairly certain I'm not initializing output correctly. Initializing it to NULL as I'm currently doing doesn't work, and I'm fairly certain it doesn't make sense either considering it would mean that output would never hold anything. It's also possible I'm just making a syntax mistake, I suppose. So I'd appreciate any ideas as to how I should initialize my output.
// source.c
#include <iostream>
#include <source.h>
#include <stdlib.h>
Source::Source()
{
Image * output = NULL;
output->SetSource(this);
}
Source::~Source() {}
Image * Source::GetOutput() const
{
std::cerr << "This function never executes due to segfault." << std::endl;
output->ResetSize(output->GetWidth(), output->GetHeight());
return output;
}
void Source::Update()
{
Execute();
}
// source.h
#include <image.h>
#ifndef SOURCE_H
#define SOURCE_H
class Image;
class Source
{
public:
Source();
virtual ~Source();
Image * GetOutput(void) const;
virtual void Execute()=0;
virtual void Update();
protected:
Image* output;
};
#endif
The below code first sets the pointer to NULL and then tries to use it, so of course there's an error.
Image * output = NULL;
output->SetSource(this);
Instead, you can initialise it by using the new keyword, like so:
Image *output = new Image;
output->SetSource(this);
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 ©);
~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!!! :-)