I tried to create my custom exception class for printing helpful message's sakes:
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <sstream>
#include <cstdlib>
class invalid_input_exception : public std::exception
{
private:
const char* input;
public:
invalid_input_exception(const char *);
const char* what() const noexcept;
};
invalid_input_exception::invalid_input_exception(const char * input) : input(input) { }
const char * invalid_input_exception::what() const noexcept
{
std::string message;
message.append("Occured on: ")
.append(input);
return message.c_str();
}
int main(int argc, char ** argv)
{
const char* str = "Aaaaa";
throw invalid_input_exception(str);
}
But it doesn't excatly work because after throwing the instance of invalid_input_exception the what() message was actually empty.
DEMO
What was wrong?
return message.c_str();
message is local to the function, and you're returning a pointer to its internal buffer. Undefined behaviour ensues.
message is a local variable, which has been destroyed when out of invalid_input_exception::what(), and the pointer returned by string::c_str() became invalid too.
You need to deep copy the content here, and might store it to the member variable input. And pay attention to the allocation and deallocation of it.
Two main problems here:
message is a local variable and will go out of scope at the end of what - thus the returned pointer is not pointing to valid string conent.
The exception class MUST make a copy of the passed message since you cannot expect the source of the message to be still valid at the point the exception will be catched.
You could go for
#include <exception>
#include <string>
class invalid_input_exception : public std::exception
{
private:
std::string input;
public:
invalid_input_exception(const char *in) : input(in)
{
input = "Occured on: " + input;
}
const char* what() const noexcept
{
return input.c_str();
}
};
or you use runtime_error as a base which has a message-copy-constructor and what:
#include <stdexcept>
#include <string>
class invalid_input_exception : public std::runtime_error
{
public:
invalid_input_exception(const char *in) :
runtime_error(("Occured on" + std::string(in)).c_str())
{ }
const char* what() const noexcept
{
return runtime_error::what();
}
};
Consider this implementation instead:
#include <stdexcept>
class invalid_input_exception : public std::runtime_error
{
public:
invalid_input_exception(const std::string& msg): std::runtime_error{ msg }{}
};
This is better for the following reasons:
The what() member function is already implemented by std::runtime_error, to work with a std::string.
Your exception class is a std::runtime_error (inheriting from std::exception dirrectly only makes sense when it is imposed by the module's design, or when you need an exception offering another data format (that is, different than a text message). Alternately, you could inherit from std::logic_error.
The class manages it's resources correctly, through the use of std::string.
Related
I am working through this problem I found on Git to brush up on some skills. Using friend is prohibited. C++ styling should be used compared to C.
Essentially, I cannot call the identify() function that belongs to the Brain member variable in my Human class. It just will not let me access it. If you can code this up, and explain where I am going wrong, that would be great.
Create a Brain class, with whatever you think befits a brain. It will have an Identify() function that returns a string containing the brain's address in memory, in hex format, prefixed by 0x.
Then, make a Human class, that has a constant Brain attribute with the same lifetime. It has an identify() function, that just calls the identity() function of its Brain and returns its result.
Now, make it so this code compiles and displays two identical addresses:
int main(){
Human bob;
std::cout << bob.identify() << "\n";
std::cout << bob.getBrain().identify() << "\n";
}
Here is what I have so far:
#pragma once
#include "Brain.h"
class Human
{
const Brain humanBrain;
public:
Human();
std::string identify();
};
#include "Human.h"
#include <iostream>
#include <string>
#include <sstream>
Human::Human()
{
this->humanBrain = new Brain;
}
std::string Human::identify()
{
Brain b = this->humanBrain.identify(); // This is essentially what I am trying to call--and I can't access it.
const Brain * ptr = humanBrain;
std::ostringstream test;
test << ptr;
return test.str();
}
#pragma once
#include <string>
#include <iostream>
class Brain
{
int age;
std::string gender;
void* ptr;
public:
Brain();
//std::string getBrain();
const std::string identify();
void setPtr(void* p);
};
#include "Brain.h"
#include <iostream>
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
const std::string Brain::identify()
{
//const Brain* bPtr = &this;
const Brain* bPtr = this;
ptr = this;
std::ostringstream test;
test << &bPtr;
std::string output = "Brain Identify: 0x" + test.str();
return output;
}
Your Human::humanBrain member is declared as type const Brain, which is correct per the instructions, however your Brain::identify() method is not qualified as const, so you can't call it on any const Brain object. This is the root of the problem that you are having trouble with.
In addition, there are many other problems with your code, as well:
Human::humanBrain is not a pointer, so using new to construct it is wrong. And, you don't need a pointer to get the address of a variable anyway. Nor do you actually need a pointer to the member at all in this project.
Human lacks a getBrain() method, so bob.getBrain() in main() will not compile, per the instructions.
Human::identify() is calling humanBrain.identify(), which returns a std::string as it should, but is then assigning that string to a local Brain variable, which is wrong (not to mention, you are not even using that variable for anything afterwards). The instructions clearly state that Human::identity() should simply call Brain::identify() and return its result, but you are not doing that.
Brain::identify() is printing the address of its local variable bPtr rather than printing the address of the Brain object that identify() is begin called on, per the instructions.
With all of that said, try something more like this instead:
Human.h
#pragma once
#include "Brain.h"
#include <string>
class Human
{
const Brain humanBrain;
public:
Human() = default;
std::string identify() const;
const Brain& getBrain() const;
};
Human.cpp
#include "Human.h"
std::string Human::identify() const
{
return humanBrain.identity();
}
const Brain& Human::getBrain() const
{
return humanBrain;
}
Brain.h
#pragma once
#include <string>
class Brain
{
int age;
std::string gender;
public:
Brain();
std::string identify() const;
};
Brain.cpp
#include "Brain.h"
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
std::string Brain::identify() const
{
std::ostringstream test;
test << "Brain Identify: 0x" << this;
return test.str();
}
For some reason the program exits when executed while testing the handling of an exception. This is the class im using as the exception recipient
#ifndef _BADALLOC
#define _BADALLOC
#include <cstring>
using namespace std;
class badalloc{
private:
char* Message;
double Number;
public:
explicit badalloc(char* M="Error",const int & N=0) {strcpy(Message,M); Number=N;}
char* what () const {return Message;}
};
#endif
this is the function member of another class that generates the exception
void ContoCorrente::Prelievo ( const double & P) throw ( badalloc )
{
if(P>0)
{
throw (badalloc ("ERROR 111XX",P));
} ...
test main :
try
{
c2.Prelievo(20);
}
catch ( badalloc e)
{
cout<<e.what()<<endl;
}
output:
Process exited after 1.276 seconds with return value 3221225477
Press any key to continue . . .
i tried defining the badalloc object to throw as "const" but to no use. any ideas?
Very simple, you are copying to an uninitialised pointer Message in your badalloc class.
You'd get this error just by constructing a badalloc object. This has nothing to do with exceptions.
EDIT
Here's a possible solution, using std::string to avoid the pointer problems.
#ifndef _BADALLOC
#define _BADALLOC
#include <string>
class badalloc{
private:
std::string Message;
double Number;
public:
explicit badalloc(const char* M="Error",const int & N=0) : Message(M), Number(N) {}
const char* what () const {return Message.c_str();}
};
#endif
I have a class that has to process data from various files. I thought about creating one function that will read the specified file and then also accept a call back so that it can use that to process the line. Below is an example class to represent what I am trying to do:
#include <iostream>
#include <vector>
#include <string>
class Example
{
std::vector<std::string> m_exampleFileData {
"test1",
"test2",
"test3"
};
public:
void doSomethingMain(const std::string& path)
{
processFile(path, doSomething);
}
private:
void processFile(const std::string& filePath, void (Example::*fpProcessLine)(const std::string&) )
{
for (const auto& line : m_exampleFileData) {
this->*fpProcessLine(line);
}
}
void doSomething(const std::string& line)
{
std::cout << "Hello: " << line << '\n';
}
};
int main(int argc, char** argv) {
const std::string filePath{"path"};
Example ex;
ex.doSomethingMain(filePath);
}
Compiler explorer: https://godbolt.org/z/LKoXSZ
The main issue is that no matter what I do I can't seem to be able to pass the function properly to processFile. Is there a way to do this in C++? How do I go about this?
You need to spell things out explicitly, in this situation:
processFile(path, &Example::doSomething);
Furthermore, you also need to slap on an extra pair of parenthesis, due to operator precedence:
(this->*fpProcessLine)(line);
I'm trying to figure out how queues work in C++ and am getting stuck when dealing with objects. I seem to only be able to get a return address instead of the name of the object (which is what I really want). It's also showing an error when I try to pop the element from the queue. My code is as follows:
Buyer.h file
#ifndef BUYER_H
#define BUYER_H
#include <string>
#include <queue>
#include "Order.h"
#include "Entity.h"
#include "Seller.h"
class Order;
class Seller;
class Buyer : public Entity {
public:
Buyer(const std::string &, const std::string &, double);
virtual ~Buyer() { }; // when step is added make this virtual
void addSeller(Seller *);
std::queue<Seller*> getSellers() const;
void addOrder(Order *);
std::queue<Order*> getOrders() const;
virtual void list() const override;
virtual void step() const override;
private:
std::queue<Order*> orders;
std::queue<Seller*> sellers;
};
#endif
Buyer.cpp file
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <queue>
#include "Buyer.h"
#include "Seller.h"
#include "Order.h"
#include "Entity.h"
using namespace std;
Buyer::Buyer(const std::string &name, const std::string &id, double balance)
: Entity(name, id, balance)
{
// initialize seller and order queue??
} // Constructor
void Buyer::addSeller(Seller *s) {
sellers.push(s);
} // addSeller
std::queue<Seller*> Buyer::getSellers() const {
while(!sellers.empty()) {
return sellers;
} // while
} // getSellers
void Buyer::addOrder(Order *o) {
orders.push(o);
} // addOrder
std::queue<Order*> Buyer::getOrders() const {
while(!orders.empty()) {
return orders;
} // while
} // getOrders
void Buyer::list() const {
Entity::list();
std::cout << "Orders:\nOrder contains:";
std::cout << "\nSellers:\n";
int i = 0;
while(!sellers.empty()) {
std::cout << sellers.front() << "\n";
sellers.pop();
} // while
} //list
void Buyer::step() const {
std::cout << "\nstep enter\n"
<< "step exit\n\n";
} // step
Any help is appreciated! Thank you!
(This isn't a full answer but it is too big to go in a comment)
It's OK to return std::queue<Order *>, and so on. However, you need to be clear on who owns the objects being pointed to; i.e. who is responsible for deleting them.
When you return a std::queue<Order *>, what happens is that the returned queue is a copy of the original one, however all the pointers point to the same object that the original one pointed to . (This is a sort of "shallow copy").
If you then delete anything in the returned queue, you will cause the original queue to malfunction because it will be accessing deleted memory.
As such, this is a fragile design because the caller can easily cause the object to screw up despite the fact that getOrders is a const function.
One "solution" is to make the containers contain shared_ptr<Order> instead of Order *. Then everything happens automatically; the caller can add or delete to his heart's content.
If it is not strictly necessary for the containers to contain pointers, consider using containers of objects: std::queue<Order>. The benefit of this approach is that the default copy and move semantics are all correct.
Another approach to consider is having getOrders() and getSellers() return a const reference, instead of returning a copy of the queue.
NB. In Buyer::getSellers(), and getOrders() if it is empty then you fall off the end of the function without returning, causing undefined behaviour. You need to either return something (what's wrong with returning an empty queue?) or throw an exception.
i've done a program. Unfortunately when trying to build it i got an error in function: undefined reference to `RzymArabException::RzymArabException(std::string).
When i was throwing a simple class like class Rzym{}; there was no errors. But when i created a class with some kind data(constructors and messages inside it doesnt work) I would be grateful if u could point where the mistake is.
#include <iostream>
#include <string>
using namespace std;
class RzymArabException{ //wyjatki
private:
string message;
int pozazakres;
public:
RzymArabException(string message);
RzymArabException(int pozazakres);
string getMessage(){return message;};
};
class RzymArab {
private:
static string rzym[13]; //konwersja z arabskich na rzymskie
static int arab[13];
static char rzymskie[7];
static int arabskie[7]; //konwersja z rzymskich na arabskie
public:
static int rzym2arab(string);
static string arab2rzym(int);
};
string RzymArab::rzym[13] = {"I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M"};
int RzymArab::arab[13] = {1,4,5,9,10,40,50,90,100,400,500,900,1000};
int RzymArab::arabskie[7] = {1000,500,100,50,10,5,1};
char RzymArab::rzymskie[7] = {'M','D','C','L','X','V','I'};
string RzymArab::arab2rzym(int x){
string s="";
if(x<1 || x>3999)
throw RzymArabException("Podana liczba w zapisie arabskim nie nalezy do dozwolonego przedzialu:(1..3999)");
else{
int i=12;
while(x>=1){
if(x>=arab[i]){
x-=arab[i];
s=s+rzym[i];
}
else
i-=1;
}
}
return s;
}
You need to provide definitions for your exception class methods, to link properly:
class RzymArabException{ //wyjatki
private:
string message;
int pozazakres;
public:
// Note the changes for the constructor methods!
RzymArabException(string message_) : message(message_) {}
RzymArabException(int pozazakres_) : pozazakres(pozazakres_) {}
string getMessage(){return message;}
};
Also I would recommend to derive any class used as exception to derive from std::exception:
class RzymArabException : public std::exception {
private:
string message;
int pozazakres;
public:
// ...
// Instead of getMessage() provide the what() method
virtual const char* what() const { return message.c_str(); }
};
This ensures that any standard compliant code will be able to catch your exception without having to use catch(...).
It's self-explanatory. You did not define that constructor; you only declared it.