I'm getting some strange error while running some C++ code that uses references. Basically I have three classes, the first contains an object of the second one while the second contains a vector of objects of the third class. This is the example code:
class MainClass {
public:
SecondaryClass myClass;
private:
void myFunction() {
int temp = 0;
const int& newValue = myClass.getFinalClassByIndex(temp).getInt();
// I add another FinalClass with the same value
myClass.addClassToVector(newValue);
// I try to add another one but the variabile "newValue" has another value
myClass.addClassToVector(newValue);
}
};
class SecondaryClass {
public:
SecondaryClass() {
myVector.push_back(FinalClass(0));
}
private:
std::vector<FinalClass> myVector;
void addClassToVector(const int& value) {
myVector.push_back(FinalClass(value));
}
FinalClass& getFinalClassByIndex(const int& index) {
return myVector.at(index);
}
};
class FinalClass {
public:
FinalClass(const int& value) : myInt(value){}
FinalClass(const int&& value) : myInt(value){}
const int& getInt(){ return myInt; }
private:
int myInt;
};
This is what happens when I run "myFunction": I get the integer value from the first object in the vector myVector and I put it in the newValue variable. Then I try to create two new FinalClass objects with the addClassToVector method, and these two will have the same integer value as the first one.
The first new object (that will be the second object in the vector) is created correctly; when I try to create the second object (the third one in the vector) the newValue variable does not have the value 0 as it should be, but it has a totally different one. It seems like the value has been moved instead of copied into the new class.
The second constructor in the class FinalClass is used when I create the class like ' FinalClass(0) ', it gives me an error if I don't use the "&&" notation.
What could the problem be in this case? I think it has something to do with the way I handle the references, but I don't understand why.
You return everything by reference. Which is fine until your vector needs to be resized, which reallocates your vector's memory and invalidates all references to that memory. Including your newValue reference. As a result your const int& newValue points to memory, which contains random data and it's a miracle your program doesn't crash at all.
Stop using references when you don't need them:
newValue = myClass.getFinalClassByIndex(temp).getInt();
and
int getInt(){ return myInt; }
even better:
auto getInt(){ return myInt; }
Related
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
I have this code, I want to fill my vector of strings from another class
class A
{
public:
B foo(const string & name) const;
}
class B
{
public:
void Add(const string & name);
vector<string> list;
}
void B::Add(const string & name)
{
list.push_back(name);
}
B A::foo(const string & name) const
{
B tmp;
tmp.Add(name);
return tmp;
}
I know this doesnt work because tmp gets destructed, but I dont know how to fix it, should i return pointer to tmp in foo()?
I know this doesnt work because tmp gets destructed
It's destroyed after it's copied to give the function's return value, so there's no problem there. There would be a problem if you returned a pointer or reference to the local variable; but you're not doing that.
I dont know how to fix it
It's not broken, so there's nothing to fix.
should i return pointer to tmp
No, that would introduce exactly the problem you're thinking of. Returning by value avoids the problem.
im working in a text-based RPG game, but when I'm setting the values to X variable, when I access that propertie again, it is in its default value, am I doing something wrong?
class Game
{
private:
bool podeAndar;
bool estaBatalhando;
Jogador _jogador;
Mapa _mapa;
public:
Game() { }
Game(Jogador _j){
_jogador = Jogador(_j.getNome());
_mapa.LoadMapa();
podeAndar = true;
estaBatalhando = false;
}
~Game(void)
{
}
Jogador getJogador() {
return _jogador;
}
void setJogador(Jogador v) {
_jogador = v;
}
}
My "Player" class
#pragma once
#include "Criatura.h"
#include <string>
class Jogador :
public Criatura
{
private:
int _cap;
public:
Jogador(std::string nome)
{
setNome(nome);
setCap(150);
}
Jogador() { }
~Jogador(void)
{
}
int getCap(){
return _cap;
}
void setCap(int v){
_cap = v;
}
}
Them my "Main" - when I set the value, when I'm following it in the debugger, it sets the value correctly, but when I access the game.getJogador().getCap() again, it has the default value 150.
int _tmain(int argc, _TCHAR* argv[])
{
Jogador _player = Jogador("Kyore");
Game game = Game(_player);
while(true){
std::cout << game.getJogador().getCap(); //print 150
game.getJogador().setCap(100); //set cap to 100
std::cout << game.getJogador().getCap(); //print 150 again
break;
}
}
In Game class, change this
Jogador getJogador() {
return _jogador;
}
to
Jogador& getJogador() {
return _jogador;
}
And add one more method only to read:
const Jogador& getJogador()const {
return _jogador;
}
Update for the questions asked in the comment
To fix your specific issue of value remaining as 150 inspite of setting a new value, converting the return type to reference is enough.
Why returning reference works?
Because, whenever your original version of getJogador() is called, a copy of the object is
created. Even though you are changing its value, you are actually
changing the value of the temporary object created, not the original
one.
So as your intention is to modify the original object, we need
to access the original one, not its temporary copy. Reference is
the better mechanism in such cases (pointer being the other mechanism, but less safer than reference)
Now about why I suggested the new over load of a const member
function, returning a const reference: this is to highlight to you that it is possible to still get the object without changing its internal state unintentionally. Your sample code does not differentiate between the two getJogador() functions.
So to understand, add these two functions to your Game class:
void DontManipulate()const { std::cout<<getJogador().getCap(); }
void Manipulate() { std::cout<<getJogador().getCap(); }
See the compiler error(s) that you get: - it should throw light on the differences.
Additionally, if you std::cout some message in both the getJogador() functions, you should be able to figure out the differences.
The problem is in your getJogador() method.
In C++, objects can be passed "by value" - which is where the program (usually) copies the object's raw data into a new location, whereas in C# and Java objects are always passed by reference (not counting C#'s structs which are passed by-value similar to C++). C++ will use the "copy constructor" to perform this copy. C++ will create the copy constructor if it isn't explicitly defined in your code, the signature has the form ClassName(ClassName& other);, the default (non-explicit) copy-constructor performs a shallow, member-wise copy operation.
In your case, your getJogador method is returning a copy of your Jogador instance field's data.
Change the method to return a reference or a pointer, like so:
Jogador& getJogador() const {
return _jogador;
}
or
Jogador* getJogador() const {
return &_jogador;
}
The const modifier informs the compiler that this method is not intended to modify the state of your Game class, so the compiler might perform certain optimizations as well as prevent successful compilation if the method does attempt to modify state.
I'm trying to make a chess program, but I want to be able to implement different AIs in it. Thus I made a abstract AIgeneric class and the derived class AIrandom off of AIgeneric. Then in my chessAI interface, I create a list of the the AIs, and try to call their getNextMove function and run into a segfault. The code is as below:
class AIgeneric {
public:
virtual int getNextMove(int*, const int &) = 0;
}
class AIrandom : public AIgeneric {
public:
AIrandom();
virtual int getNextMove(int*, const int &);
}
class chessAI {
public:
chessAI();
~chessAI();
void setAI();
int getNextMove(int*, const int &);
private:
vector<AIgeneric*> AIlist;
vector<string> names;
int selectedAI;
};
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
int chessAI::getNextMove(int * board, const int & color) {
return AIlist[selectedAI]->getNextMove(board, color); //segfault on this line
}
It'd be great if anyone could help me on this problem!
Edit: I do set selectedAI to 0 before calling getNextMove.
In this code:
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
You store a pointer to a local variable into your vector. After the constructor returns that pointer is no longer valid.
Remember that all local variables are stored on the stack, and the stack is reused in other functions. So when you use the pointer in the vector, it now points to some other functions memory and not the one object you declared.
This can be solved in three ways:
Allocate the object on the heap:
AIlist.push_back(new AIRandom);
Not using pointers at all.
Use smart pointers, such as std::unique_ptr.
You call selectedAI = -1; and then AIlist[selectedAI]->.... What do you expect AIlist[-1] to be, other than undefined behavior?
I expect this is because AIlist[selectedAI] is out of bounds. You can confirm this by replacing it with AIlist.at(selectedAI). Keep in mind that this index is -1 immediately after the constructor...
I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(¤tThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int ¤tThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int ¤tThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int ¤tThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int ¤tThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.