How to use a variable in the same struct it's defined in? - c++

I am making a rogue-like ASCII game and made a struct called "Armor" and I want to use the name variable in the struct to have the path to whatever the name is.
struct Armor {
bool equipped;
std::string name;
int getBuff(int buff) {
std::fstream item;
std::string line;
std::string response;
std::string value;
item.open("../Data/Items/" + name + ".item", std::fstream::in);
if (item.fail())
errorQuit("ERROR: There was a problem loading armor type .ITEM file."); // Error and quit function
while (!item.eof()) {
getline(item, line);
response = split(line, '=', 0); // Splits string
if (response == "buff" + std::to_string(buff)) {
value = split(line, '=', 1);
break;
}
}
item.close();
return std::stoi(value);
}
};
Then I called it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1);
But this throws an Unhandled exception error.
I changed it so that getBuff takes 2 parameters, int buff and std::string itemName. and replaced name in the path with itemName;
Then I tried calling it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1, sword.name);
But this throws the same error.
I'm confused as to why I can't use the name variable as it has already be defined. Is there any other way I can use the name variable like that?

I see you've just edited your comment to say you've figured your problem out, but I just want to add something else that may be helpful:
Without seeing how errorQuit() is defined, there's a potential problem in your getBuff() function. If the expression if (item.fail()) evaluates to true, the function may continue on trying to process the data (unless errorQuit() somehow breaks out of the program or something, which probably isn't the best approach).
Basically, testing for fail() may or may not provide the behavior you require in all scenarios, depending on what bits are set in the stream state. Implementations vary, but... if the file fails to open, failbit and/or badbit will be set, but not eofbit. getline() will see the error state and so it will not try to read from the stream when you call it. But that also means the eofbit will never be set!
There's lots of different "techniques" to file reading. Some people prefer an RAII approach. Others like looping on getline(). Or you could even just use good() to check the error state if you don't care what happened and simply want to know if everything is fine or not.
In any case, you might be interested in the info on this page: std::ios_base::iostate.

Thanks for all your help but I figured it out on my own.
I just made a stupid error that I overlooked like an idiot.
It is searching for buff + int (e.x. buff1) in the file but there are multiple lines that contain that word so I guessed that messed it up. I just made an adjustment to the if statement and it is working as expected.
Sorry to bother you!

your getBuf() function fails on some io-operation and throws an exception.You dont handle exceptions and thus the application quits with the appropriate message. Try surrounding the call to getBuf with try/catch (add the includes to iostream and stdexcept)
try {
int buff = sword.getBuff(1);
}
catch (const std::exception &e) {
std::cout << e.what() << std::endl;
}

Related

unable to determine rapidjson type / difficult to read triple nested strings

I'm trying to use cereal to deserialize a JSON message. The (current) message structure is as follows:
"A":"B",
"C":{"D":"E","F":"G","H":"I"},
"J":"K",
"L":"M",
"N":{"O":{"P":"Q"}}}
The most important piece of data is "Q."
I can read all the normal strings easily. I was able to read the top-level items easily. I eventually was able to read "D"-"I" by treating "C" as an array (despite the lack of "["and "]"). However, I am unable to archive "N" as a string, array, vector, or object. It simply fails the respective IsString(), IsObject(), etc check on the iarchive(C); line. I see a GetType(), but I don't know to call that on "N" because anything I try to do with "N" fails.
I then was able to break the string down to just
{"O":{"P":"Q"}}
great, so just "C", but even simpler. Unfortunately, I had the same issue as before.
I then broke it down to just {"P":"Q"} and was able to finally get the value of Q via iarchive(value)
std::string msgtype,protocol_version, command, radio1_frequency,value;
std::string unit_id[3];
std::stringstream ss(msg->get_payload());
{//at this point, ^ss has the same format as outlined above, from "A" to "Q."
cereal::JSONInputArchive iarchive(ss);
iarchive(CEREAL_NVP(msgtype), CEREAL_NVP(protocol_version), CEREAL_NVP(command),CEREAL_NVP(unit_id));<-----------------------
}
rapidjson::Document doc;
doc.Parse((msg->get_payload()).c_str());
const rapidjson::Value& vars = doc["variables"];//<--this string is N
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
vars.Accept(writer);
std::stringstream sst(sb.GetString());
std::cout << sst.str() << "\n"; //here, sst has {"O":{"P":"Q"}}
doc.Parse(sb.GetString());
const rapidjson::Value& val = doc["radio1_frequency"];//<--this string is O
sb.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writerTwo(sb);
val.Accept(writerTwo);
std::cout << sb.GetString() << "\n";//ss3 will now have {"P":"Q"}
std::stringstream ss3(sb.GetString());
{
cereal::JSONInputArchive iarchive(ss3);
iarchive((value));
std::cout << value << '\n';//Q
}
if I add ,CEREAL_NVP(variables) to the line with the arrow, I get the following output:
terminate called after throwing an instance of 'cereal::RapidJSONException'
what(): rapidjson internal assertion failure: IsString()
Child terminated with signal = 0x6 (SIGABRT)
To be clear, I get the result that I want, Q. I just feel like there must be a better way. I feel like the root of the problem is that I am unable to identify what type N is. Since I don't know the type, I don't know how to properly archive it in cereal. What can I do better inside the realm of C++11 and cereal, which uses rapidjson?
I wonder if it is because "O" has a number in the middle of the string and that is throwing it off. I should hope not because that's a valid string I believe
edit: I forgot to mention that "O" can change. so I won't be able to hardcode that in doc["N"]["O"]["P"]

Returning null in a method that accounts for multiple conditions

Consider the following method:
private static String method (String string) {
if (string.equals("conditionOne")) {
return value;
} else if (string.equals("conditionTwo")) {
return symbol;
} else {
return null;
}
}
Let's say I am checking for two conditions, conditionOne and conditionTwo. Also, assume that some other part of the program ensures that only these two cases will ever happen. Since the method has to return something for all cases to avoid a compiler error, is it okay to return null for the final else block just for syntactical purposes since that part will never execute?
Edit: For clarity, I'd like to mention that the compiler gives me an error ("Expecting return statement") if I don't include that last else block. Other than to returning null (or an empty string, as pointed out by Anthony below), is there another way to write this method so that this does not happen?
Thanks
You're describing a very common scenario while programming. You intend for a certain thing to never happen, but the compiler also knows it could happen. The proper way to handle such code paths is to ensure that they are never reached, generally by throwing an AssertionError or a RuntimeException such as IllegalArgumentException, IllegalStateException or UnsupportedOperationException. This is referred to as failing-fast.
In your case I would throw an IllegalArgumentException as that's clearly what's happened - your method expects exactly two inputs; anything else is forbidden and you should fail-fast in such cases. Effective Java Item 38 also discusses this.
private static String method (String condition) {
if (condition.equals("conditionOne")) {
return value;
} else if (condition.equals("conditionTwo")) {
return symbol;
}
throw new IllegalArgumentException("Invalid condition '" + condition +"'");
}
Now you can be confident the only inputs this function will support are the ones it is designed to support. Even better, anyone calling your method incorrectly will get a clear, actionable error message.
The Guava User Guide has a good overview of different kinds of failures and when you should raise them.
You could also avoid this issue other ways - namely by defining a better method signature. It looks like you're defining a "stringly-typed" API; using an enum would help prevent callers from passing in erroneous parameters. See also Effective Java Items 50 and 30.
In rare cases (generally when dealing directly with user input) you'll want to fail-soft rather than fail-fast. This is common with confirmation dialogs; if you ask the user to enter "Yes" or "No" it's generally sufficient to simply check whether they entered "Yes" - whether they entered "No" or "Uhhhh", you'll just treat it as not-"Yes".
As you have defined the function as returning a String, it would be more correct to have
if (string.equals("conditionOne")) {
return value;
} else if (string.equals("conditionTwo")) {
return symbol;
} else {
return "";
}
You can write something like this:
if (string.equals("conditionOne")) {
return value;
} else if (string.equals("conditionTwo")) {
return symbol;
}
return "";
or like this:
string rval = "";
if (string.equals("conditionOne")) {
rval = value;
} else if (string.equals("conditionTwo")) {
rval = symbol;
}
return rval;
or like this
if (string.equals("conditionOne")) {
return value;
} else if (string.equals("conditionTwo")) {
return symbol;
}
throw;
edited.
If you've already guaranteed that the string will always equal either conditionOne or conditionTwo, then writing the 3rd else condition is not necessary.
It's equivalent to adding code that does not check if it's either conditionOne or conditionTwo. It's better off to remove it.
Edit Seeing your edit, I would recommend the above solution of returning "" since it's a string.

C++ - Continuing a while loop upon exception

When an exception is encountered in C++, does the program automatically terminate upon catching it. Is there a way that ,if the exception was caught within a loop, I could just skip the rest of the loop and go straight to the next iteration?
There are a number of different ways to solve this problem.
Create a member function that checks whether a move is valid before making it. The calling code will need to call this function before calling advance, and only call advance if the move is valid.
Make the advance member function return a value indicating whether the player's position was advanced. The calling code will need to test the return value to decide whether to print the board or print a "try again" type of message.
Make the advance member function throw an exception if the move is invalid. The calling code will need to catch the exception.
There are lots of other ways to solve this problems.
Well first of all, if that snipped of code is EXACTLY how you copy-pasted it, it has some syntax errors. This is how it should be written:
int main() {
...
Person *p = new Person("Neo");
...
string in;
while(cin >> in) {
if (in == "q") {
break;
}
else if (in == /*One of the eight directions North ... Northwest*/) {
p->advance(in);
} //this bracket here ends the if. after the parentheses, nothing else will execute
else {
cerr << "Input one of the eight directions" < endl;
}
}
}
So yeah, if I understood correctly your problem, adding that closing bracket there should solve it. I hope this is what you needed and that it was helpful

Stop process if there is an error in the constructor

In a utility class file, I want to open a file to read or write it.
If I can't open it, I don't want to continue the process.
FileUtility::FileUtility(const char *fileName) {
ifstream in_stream;
in_stream.open(filename);
}
FileUtility fu = FileUtility("bob.txt");
fu.read();
fu.write();
File bob.txt doesn't exist, so I don't want method to read and write.
Is there a clean way to do it?
When construction of an object fails in C++, you should throw an exception, or propagate the exception from the failed construction of the subobject.
FileUtility(const char* filename) {
std::ifstream in_stream;
in_stream.exceptions(std::ios_base::failbit);
in_stream.open(filename); // will throw if file can't be opened
}
In the calling code you can choose to handle the exception:
try {
FileUtility fu = FileUtility("bob.txt");
} catch (std::ios_base::failure) {
printf("Failed to open bob.txt\n");
exit(EXIT_FAILURE);
}
// do other stuff
Or, if you don't catch the exception, the runtime will just call std::terminate(), which will print out its own error message, which may or may not be helpful:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Aborted
There are generally four ways error state can be communicated from a callee to a caller:
1. Direct return value (return code or OUT parameter).
A return code is not possible for a constructor call, although an OUT parameter is. However, it's somewhat invasive to require every function to provide its return code or an OUT parameter for this purpose, so I don't like this solution in general, although it is certainly heavily used in various libraries and APIs. You could use this approach by adding a pointer or reference parameter to your constructor, to which the caller could provide the address of some local error variable, into which the constructor could store a possible return value. I don't recommend this.
2. Exceptions.
There is a somewhat polarized debate on the pros and cons of exceptions, in both C++ code and in other languages. I may take some downvotes for saying this, but my personal opinion is that exceptions should be avoided like the plague. See http://www.joelonsoftware.com/items/2003/10/13.html for someone who shares my view. But this is a workable solution if you're so inclined. See #Brian's answer for a good demonstration of this solution.
3. Object attribute.
The std::ifstream object actually does this, so you can leverage that. (Actually, from your example code, you define your std::ifstream as a local variable in the constructor, which implies it won't persist after the call, but since you call some kind of read() and write() methods on the constructed object, that implies that you do persist it after the call, so I'm going to assume the latter is the correct inference.) You can leverage that, by calling std::ifstream::is_open(). If you want to maintain encapsulation of the std::ifstream, you can define your own is_open() equivalent on FileUtility that will simply return in_stream.is_open();, again, assuming it is retained as an attribute on your FileUtility class.
struct FileUtility {
ifstream ifs;
FileUtility(const char* fileName);
bool is_open(void) const;
};
FileUtility::FileUtility(const char* fileName) { ifs.open(fileName); }
bool FileUtility::is_open(void) const { return ifs.is_open(); }
FileUtility fu = FileUtility("bob.txt");
if (!fu.is_open()) return 1;
Alternatively, you could create a whole new error state layer just for the FileUtility class, and propagate the std::ifstream error through that. For example:
struct FileUtility {
static const int ERROR_NONE = 0;
static const int ERROR_BADFILE = 1;
ifstream ifs;
int error;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) : error(ERROR_NONE) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (fu.error != FileUtility::ERROR_NONE) return 1;
These are reasonable solutions.
4. Global error state.
I wouldn't be surprised if some programmers were to respond with a "that sounds like a bad idea" reaction to this possible solution, but the truth is that many extremely successful and prominent code bases use this solution for communicating error state. Perhaps the best examples are the errno variable used by the C Standard Library (although it should be mentioned that errno sort of works in conjunction with direct return codes), and the GetLastError() system used by the Windows C API. I suppose some might argue that that's really the "C approach", and exceptions are the "C++ approach", but again, I avoid exceptions like the plague.
As an aside, multithreadedness is not a problem for this solution, because errno and GetLastError() both use thread-local error state, rather than true global error state.
I like this solution best, because it's simple, extremely uninvasive, and can easily be reused by different code bases, provided of course that you define the error framework (basically the thread-local variable and possibly the ERROR_NONE macro/global; see below) in its own library, in which case your code gains a consistency when it comes to error handling.
Example:
#define ERROR_NONE 0
thread_local int error = ERROR_NONE;
struct FileUtility {
static const int ERROR_BADFILE = 1;
ifstream ifs;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (error != ERROR_NONE) return 1;
This is the solution I'd recommend; otherwise I'd go with an object attribute solution.

C++ Can an fstream object be set to automatically write a newline on each call to <<?

I've created an fstream object to write info to files.
I write strings to the new file like
fStreamObject << "New message.\n";
because I want each << to print a string to the next line.
I want to be able to set a property and make a call like
fstreamObject << "New message.";
which will write the string to the next line.
Are there flags/settings for fstream objects that allows this to be done?
I've seen the different file modes (i.e. ofstream::in, ofstream::out, etc.), but I couldn't find one that auto writes to a new line. Also, I'm not looking to write my own solution. I want to be able to use a built in feature.
No, there are no readily configurable capabilities of that sort within the standard streams.
You may have to subclass the stream type and fiddle with operator<< to get this to work the way you want, or do it with a helper function of some description:
fstreamObject << nl("New message.");
(but that's hardly easier than just having the \n in there (for a string, anyway).
It depends on what you mean by "setting the stream". If we consider this to be fairly broad then the answer happens to be "yes"!
Here is how:
Create a stream buffer which inserts a newline every time it is flushed, i.e., when sync() is called. Otherwise it just forwards characters.
Change the file stream's stream buffer to use this stream buffer filtering to the file stream's stream buffer.
Set the flag std::ios_base::unitbuf which causes a flush after every [properly written] output operation.
Here are is the example code to do just that:
#include <iostream>
class newlinebuf
: public std::streambuf {
std::ostream* stream;
std::streambuf* sbuf;
int overflow(int c) { return this->sbuf->sputc(c); }
int sync() {
return (this->sbuf->sputc('\n') == std::char_traits::eof()
|| this->sbuf->pubsync() == -1)? -1: 0;
}
public:
newlinebuf(std::ostream& stream)
: stream(&stream)
, sbuf(stream.rdbuf(this)) {
stream << std::unitbuf;
}
~newlinebuf() { this->stream->rdbuf(this->sbuf); }
};
int main() {
newlinebuf sbuf(std::cout);
std::cout << "hello" << "world";
}
Although this approach work, I would recommend against using it! On problem is that all composite output operators, i.e., those using multiple output operators to do their work, will cause multiple newlines. I'm not aware of anything which can be done to prevent this behavior. There isn't anything in the standard library which enables just configuring the stream to do this: you'll need to insert the newline somehow.
No, the C++ streams do not allow that.
There is no way to decide where one insertion stops and the next starts.
For example for custom types, their stream-inserters are often implemented as calls to other stream-inserters and member-functions.
The only things you can do, is write your own class, which delegates to a stream of your choosing, and does that.
That's of strictly limited utiliy though.
struct alwaysenter {
std::ostream& o;
template<class X> alwaysenter& operator<<(X&& x) {
o<<std::forward<X>(x);
return *this;
}
};