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.
Related
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; }
Couldn't find the answer in any similar-named question.
I want a user to be able to initialize a string member at any point in the lifetime of an object, not necessarily on construction, but I want them to know that the object is invalid until the string is initialized...
When creating a simple class, say the following:
#include <string>
class my_class {
public:
my_class() : _my_str() { }
my_class(const std::string & str) : my_class() {
set_my_str(str);
}
std::string get_my_str() const {
return _my_str;
}
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
std::string _my_str;
};
and a user creates an empty instance of the class (i.e. using the empty constructor), _my_str will be an empty/uninitialized string?
So, I see two ways of handling behavior: the way mentioned above, where an empty string is returned, or a possible second way:
#include <string>
class my_class {
public:
my_class() : _my_str(), _my_str_ptr(nullptr) { }
my_class(const std::string & str) : my_class() {
set_my_str(str);
}
std::string * get_my_str() const {
return _my_str_ptr;
}
void set_my_str(const std::string & str) {
_my_str = str;
_my_str_ptr = &_my_str;
}
private:
std::string _my_str;
std::string * _my_str_ptr;
};
Where you return a nullptr, and you maintain a pointer to a local variable?
Is that valid behavior? Which way is preferred and why? Wouldn't the second way be better since you are telling the user, "listen, this object is currently invalid, you need to initialize it" while still implying that you are managing the lifetime of such object.
_my_str will be an empty/uninitialized string?
Empty, yes. Uninitialized, no. It's completely initialized (to an empty string).
Where you return a nullptr, and you maintain a pointer to a local variable?
Is that valid behavior?
Yes it's valid, but
Which way is preferred and why? Wouldn't the second way be better since you are telling the user, "listen, this object is currently invalid, you need to initialize it" while still implying that you are managing the lifetime of such object.
It makes absolutely no sense to maintain two distinct member variables for this. It sounds like what you need is std::optional (or the equivalent in Boost, boost::optional), so that _my_str has two states: empty/invalid (contains no string) and non-empty/valid (contains a string):
#include <string>
#include <experimental/optional>
using std::experimental::optional;
class my_class {
public:
my_class() /* default-initializes _my_str as empty */ { }
my_class(const std::string & str) : _my_str(str) { }
const std::string * get_my_str() const {
if (_my_str) // if it exists
return &*_my_str; // return the string inside the optional
else
return nullptr; // if the optional is empty, return null
}
/* Or simply this, if you don't mind exposing a bit of the
implementation details of the class:
const optional<std::string> & get_my_str() const {
return _my_str;
}
*/
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
optional<std::string> _my_str;
};
If "" (an empty string) can be used as a sentinel value to signify the "empty/invalid" state in your case, then you can just do this:
#include <string>
class my_class {
public:
my_class() /* default-initializes _my_str as "" */ { }
my_class(const std::string & str) : _my_str(str) { }
const std::string * get_my_str() const {
if (!_my_str.empty()) // if it'a non-empty
return &_my_str; // return the non-empty string
else
return nullptr; // if it's empty, return null
}
void set_my_str(const std::string & str) {
_my_str = str;
}
private:
std::string _my_str;
};
In general, the pattern you're referring to is called Null object pattern.
The "oldest way" of implementing it was using one of possible values of a variable and reserving it for "no value" meaning. In case of a string an empty string commonly was used in such a way. Obviously not always possible, when all values were needed.
The "old way", was always using a pointer - (const T* get_t() const). This way the whole range of variable values could be meaningful, and still "no value" semantics were available by means of returning a null pointer. This was better, but still pointers are not as comfortable to use, not safe. Nowadays, pointers are usually bad engineering.
The modern way is optional<T> (or boost::optional<T>).
An empty std::string value is not per definition invalid. It is just empty.
On important difference is that the second "get_..." approach does not copy the object but gives the user a non const pointer to the internal string which leads to violation of const correctness since you imply that the class may not be changed by having const at the get method while still providing a pointer that may change the internal state.
If your logic implies that "empty string" == "invalid" and if this is a possible state there is not much of a difference whether the user must do
if (get_my_str())) // use valid pointer to nonempty string versus
if(!get_my_str().empty()) // use valid nonempty string
I think.
You'd want to return std::string const & from your get method and leave it to the user wether to copy the object or not.
4.1. No forced copy (versus by value return std::string)
4.2. No pointer which may be nullptr and accidentally dereferenced.
4.3. Passing around and storing a pointer which may outlive the object is more common that dangling references.
I want a user to be able to initialize the string later on, not necessarily on construction, but I want them to be able to know that the object is invalid until the string is initialized...
The question is: Is an empty string actually a "valid" value after proper initialization?
If yes: use optional to add one additional state signaling validity.
If no: let the emptyness of the string stand for invalidity of your object.
I am having issues with trying to figure out how I would turn a data member inside a class (which was originally an int) into a pointer to a dynamically allocated piece of memory.
I know I can do int *num = new int under normal circumstances, but how would I initialize it in a class?
My teacher did an amazing job of not explaining this in the crappiest way possible in class -_-.
This is an example of the class and the constructor.
The header
class Double
{
private:
double *val;
The .cpp
Double::Double()
{
this->equals(0.0);
}
Double::Double(const Double &d)
{
this->equals(d.val);
}
Double::Double(const double &d)
{
this->equals(d);
}
Double::Double(const Interger &i)
{
this->equals(i.toInt());
}
//New overloaded constructor using strings
Double::Double(const string &s)
{
this->equals(s);
}
void Double::equals(const double &d)
{
this->val = d;
}
All I know is I have to make the data member a pointer now, but I have no idea how to create the new memory. I tried looking this up but I could not find an example of how to do DAM inside an actual class for its memory and constructor.
EDIT
Solution was a simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.
SOLUTION TO MY PROBLEM (So the problem is solved)
Solution was simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.
Deconstructors will have to be created to clear the memory though.
so I've been working on a program where I have a class called CDistance, here it is,
class CDistance
{
private:
int feet, inches;
public:
CDistance();
CDistance(int, int);
void setDist();
void printDist() const;
CDistance add(const CDistance&) const;
};
part of what I need to do is to create an array of 5 of these objects, set the feet and inches on each one of them, and then add them together without changing the original variables. This is the function definition, as you can see, it's working with all constant members, so it's a matter of figuring out how to reference the variables, but most importantly, getting them back into a CDistance type to be returned. Should I create a new CDistance type within this function to work with the ref
CDistance CDistance::add(const CDistance&) const
{
}
That's where I've been stuck, I'm kind of confused about the whole pointers and encapsulation deal. I'm new to programming, and have learned that the hard way, but if someone could help me out with this, I would really appreciate it
Should I create a new CDistance type within this function to work with the ref
Yes, you'll need a new object to modify and return:
CDistance add(const CDistance& other) const {
CDistance result = *this; // Copy this object
result.feet += other.feet; // Add the other object...
result.inches += other.inches; // ... to the copy
return result; // Return the copy
}
Note that this isn't complete; there's one deliberate error, and an unknown number of accidental errors, which you'll need to fix yourself.
You can simply return a local result instance from your function:
CDistance CDistance::add(const CDistance& other) const
{
CDistance result(*this);
// Calculate the result using result.feet, result.inches and
// other.feet, other.inches
return result;
}
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...