I've been bragging a friend of mine about C++ (scopes and RAII and static typing ftw) (I'd be embarrassed if this were me and not ask :P) but as I'm looking at it I am puzzled as tp what is going wrong. I hope you guys can help. She's coming from Java hence the CamcelCase
ListIndexOutOfBoundsException.h
#ifndef LISTINDEXOUTOFBOUNDSEXCEPTION_H_
#define LISTINDEXOUTOFBOUNDSEXCEPTION_H_
#include <exception>
namespace Structures {
class ListIndexOutOfBoundsException: public ::std::exception {
public:
ListIndexOutOfBoundsException(int index, int length);
virtual const char* what() const noexcept;
virtual ~ListIndexOutOfBoundsException() noexcept;
private:
const char* errorString;
};
}
#endif /* LISTINDEXOUTOFBOUNDSEXCEPTION_H_ */
ListIndexOutOfBoundsException.cpp
#include "ListIndexOutOfBoundsException.h"
#include <string>
#include <sstream>
namespace Structures {
using ::std::stringstream;
ListIndexOutOfBoundsException::ListIndexOutOfBoundsException(int index,int length) {
stringstream errorText("List index (");
errorText<<index<<") out of bounds! (list length: "<<length<<")";
errorString = errorText.str().c_str();
}
const char* ListIndexOutOfBoundsException::what() const noexcept {
return errorString;
}
ListIndexOutOfBoundsException::~ListIndexOutOfBoundsException() noexcept {
delete errorString;
}
}
When thrown this happens:
terminate called after throwing an instance of
'Structures::ListIndexOutOfBoundsException'
what(): OfBoundsException
I cannot work out where "OfBoundsException" has come from. What is going on!?
When the constructor goes out of scope, errorText no longer points to valid data, so all bets are off when you call what() (it invokes undefined behavior). The easiest fix is to derive from std::runtime_error, as that keeps a std::string (or equivalent) which is valid for the lifetime of the exception.
The problem is this
errorString = errorText.str().c_str();
errorText was a local object to the constructor that went out of scope and freed the memory it was using for it's c_str().
Try replacing errorString with a char errorString[SomeLimit]; and using basic string operations to write to it. Using a stringstream is somewhat overly complex for an exceptionhandler.
Related
In the C++ library I'm writing I've extended std::runtime_error (just to have a unique type -- I don't need anything beyond a what-string). But I sometimes want to catch the exception at the user entry point to append additional context information to the what string, and then rethrow it. But there does not appear to be anyway to modify the what string of runtime_error. Why is it designed that way? Is it to avoid possible out-of-memory condition during the realloc of the internal string buffer (which would lead to a new exception)? Or do they just want to encourage the use of nested exceptions to do this kind of thing? (Nested exceptions seems unnecessarily cumbersome since it's all within the context of one library, but maybe I'm being wrong-headed.) My current approach is to override the virtual what method and return my own (appendable) string:
#include <stdexcept>
#include <string>
class MyException : public std::runtime_error
{
public:
explicit MyException(const std::string& what_arg) :
MyException(what_arg.data())
{
}
explicit MyException(const char* what_arg) :
runtime_error(""),
what_("MyException: ")
{
append(what_arg);
}
const char* what() const noexcept
{
return what_.data();
}
void append(const char* msg)
{
what_.append(msg);
}
void append(const std::string& msg)
{
what_.append(msg);
}
private:
// As near as I can tell, there is no way to modify the what arg
// of runtime_error, so I don't use it and make make my own what
// arg here.
//
std::string what_;
};
So is this approach evil? Is there a better way?
I am a noob working on my very basic hobby program on chemestry, where i have created a class compound and added string compundname, but i want to design it in such a way that when i put in some invalid element in compund string, ex- NaMmO4 the compiler will not let me create object and instead come with an error something like "Mm invalid element"
Note:: my concern here is only with error handling.
example
compound sodiumsalt {"NMmO4"}
compiler should give error something like -
Mm is an Invalid element. cannot create object.
You are confused about the job of the compiler and what compiler-errors are.
Compiler errors are mostly sintax error and easy-to-spot running errors, where the compiler doesn't know what are you trying to do. To write the wrong string name will never be a compiler error. Also, it seems the name will be written at running time, which happens after compiler-time.
Might want to do something like this:
#include <iostream>
#include <exception>
using namespace std;
//some people are heavily against it, but I think is easier to use it if you are a beginner.
enum class elem_t{elem1, elem2, elem3};
class outOfBound: public exception
{
virtual const char* what() const throw()
{
return "Error: Accessed an element that doesn't exists.";
}
} noElem;
class Compound{
public:
Compound(elem_t* elems, int size){_elems = elems; _size = size;}
//can't include something is not part of elem_t
elem_t operator()(unsigned pos) const {if(pos < _size) return _elems[pos]; else throw noElem;}
int size() const{return _size;}
private:
elem_t* _elems;
int _size;
};
int main()
{
elem_t a[] = {elem_t::elem2, elem_t::elem1};
Compound first(a,2);
return 0;
}
The only basic thing I didn't do is a print() or operator<<, but it should be easy.
I keep getting this error and I'm not sure how to correct it as I am given no errors in my code editors. I have looked up similar issues, but I am still having trouble to understand how to apply the solutions here. I've tried altering my code for several hours now, but to no avail. Any help would be appreciated. I have provided my .h and .cpp files below.
ErrorMessage.h
#ifndef SICT_ERRORMESSAGE_H
#define SICT_ERRORMESSAGE_H
#include <iostream>
namespace sict {
class ErrorMessage {
char* message_; //pointer that holds the address of the message stored in current object
public:
explicit ErrorMessage(const char* errorMessage = nullptr); //receive address of a C-style nullterminate string holding an error message
ErrorMessage(const ErrorMessage& em) = delete; //deleted copy constructor that prevents copying of an ErrorMessage object
ErrorMessage& operator=(const ErrorMessage& em) = delete; //deleted assignment operator that prevents assignment of ErrorMessage object to current object
virtual ~ErrorMessage(); //deallocates any memory that has been dynamically allocated by the current object
void clear(); //clears any message stored by current object and initialize object to safe, empty state
bool isClear() const; //return true if object is in a safe, empty state
void message(const char* str); //stores a copy of the C-style string pointed to by str
const char* message() const; //return address of the message stored in current object
};
//helper operator
std::ostream& operator<<(std::ostream& os, const ErrorMessage& err);
}
#endif
ErrorMessage.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include "ErrorMessage.h"
namespace sict {
ErrorMessage::ErrorMessage(const char* errorMessage) {
if(errorMessage == nullptr) {
message_ = nullptr;
}
else {
message(errorMessage);
}
}
ErrorMessage::~ErrorMessage() {
delete [] message_;
}
void ErrorMessage::clear() {
delete [] message_;
message_ = nullptr;
}
bool ErrorMessage::isClear() const {
if(message_ == nullptr) {
return true;
}
else {
return false;
}
}
void ErrorMessage::message(const char* str) {
delete [] message_;
message_ = new char[strlen(str) + 1];
strcpy(message_, str);
}
const char* ErrorMessage::message() const {
return message_;
}
std::ostream& operator<<(std::ostream& os, const ErrorMessage& err) {
if(!err.isClear()) {
os << err.message();
}
return os;
}
}
It's not surprising your code made it through editor syntax checks and compilation - it's valid code. It's just got an incorrect pointer somewhere.
This may mean that your'e accidentally dereferencing something , or perhaps passing a value somewhere you should be passing a pointer. You should get a compile time warning about that kind of stuff.
Another possibility is that you're failing to initialize some pointer, and its value happens to be 0xb75....
Clearly, neither you nor I are not likely to guess from whence this error originates. As Sam Varshavchik pointed out in a comment, you don't even know if the code you posted is the source of the error. Even if you guess your way through this one ( or perhaps keenly observe, Sam ), it's just plain silly to try to write C++ that way.
What you need is a debugger. A debugger is a program you run your program within, and it keeps track of the program's state so that when you have a memory violation, the debugger can produce a backtrace showing where in your source code the error occurred. You also have to compile your program with debugging support, so that the debugger has markers it can use to refer back to the source code.
It's a process far beyond the scope of your question, but one that's easy to learn about once you know what you're going for. Look for one that integrates with your IDE, if possible, as you're leveraging your development environment heavily. It's not unlikely that you already have it set up- you might just need to use it. Search for C++ debugging in the context of your editor first - if it turns up nothing, consider searching under your compiler suite, whatever that may be ( if your'e using open source, you're probably using gcc, and the matching debugger is gdb ).
You're about to gain a far more accurate understanding of what it is to program C / C++. Good luck.
Say I want to write a vector-based string (String) just for the heck of it and I want an efficient c_str() operation on it.
Seems easy enough if I simply ensure the following:
//Make sure end() points to a '\0' and that '\0' is in allocated space
void afterEachNonConst() { reserve(size()+1); *(end()) = '\0'; }
Then c_str() is "just" begin() converted to const char*:
//Return C-string
const char* c_str() const { return (const char*)(&((*this)[0])); }
(I don't know how to do it shorter; the type system seems very unwilling to convert vector<char>::const_iterator to const char* even though they should be the same).
With that I want to override every non-const non-void method (except for and reserve) with:
auto ret = vector::method(arg1, arg2, arg3, ...);
//^can't it be just something like `auto ret = super();` ??
afterEachNonConst();
return ret;
and every non-const void method with:
vector::method(arg1, arg2, arg3, ...);
afterEachNonConst();
I guess there's no reasonably elegant way to just let C++ metaprogramming do all the work (?). Can I at least get a listing of all vector method signatures into my text editor somehow?
Here's a compilable example I played with:
#include <iostream>
#include <vector>
#include <cstring>
#include <cassert>
class String : public std::vector<char> {
public:
//Initialize from c-string
String& operator=(const char* cstr) {
size_t length = strlen(cstr);
reserve(strlen(cstr) + 1);
resize(length);
for(iterator ptr = begin(); *ptr++=*cstr++; ); //this will copy the '\0' too, but only at end()
return *this;
}
String(const char* cstr){ (*this) = cstr; }
//Return C-string
const char* c_str() const { return (const char*)(&((*this)[0])); }
void push_back(char value){
vector::push_back(value);
afterEachNonConst();
};
private:
//Make sure end() points to a '\0' and that '\0' is in allocated space
void afterEachNonConst() { reserve(size()+1); *(end()) = '\0'; }
};
int main(int argc, char **argv)
{
using namespace std;
String a = "foobar";
assert(a.size() == strlen(a.c_str()));
a.push_back('_');
a.push_back('1');
assert(a.size() == strlen(a.c_str()));
cout<<a.c_str()<<endl;
return 0;
}
What you want to do cannot be done with metaprogramming. You'd need reflection as part of the language, which is IMHO sadly a missing feature of C++.
To get a list of the member functions of std::vector I'd go and open the standard, N4431 §23.3.6 and try to extract them from there.
If this is too "much work" you could also try to implement something using libclang or libTooling, though this seems by far easier as it really is. (I just had to do something similar)
Since the syntax of C++ is so extremely complicated, especially in combination with templates, parsing it is really hard. Sadly using the above libraries it's also very hard to reproduce a parsed member function declaration.
My teacher asked the class to fix the error in this program. Actually it seems to be a crappy program; I just typed it exactly how it is in the sheet, and got this error:
Well Now I have just change some things, but get this exception at run time: Microsoft C++ exception: [rethrow] at memory location 0x00000000..
The code is now like so: (The variable an class names are now in spanish, sorry for the inconviniences)
#include <iostream>
#include <exception>
#include <stack>
using namespace std;
class EPilaVacia : public exception{
public:
const char* what() const throw(){
return "Error: Pila Vacía";
}
};
template <class T, int max=100>
class Pila{
private:
stack<T*> *pila;
int cont;
public:
Pila() : cont(0){
pila=new stack<T*>();
}
virtual void apilar( T* pt){
if(cont<max){
pila->push(pt); //respuesta 2
}
}
virtual void apilar(T t){
if(cont<max){
pila->push(&t); //respuesta 3
}
}
T tope() const throw (EPilaVacia){
if(cont>0){
pila->top(); //respuesta 4
}else{
throw ; //respuesta 5
}
}
T& desapilar() throw (EPilaVacia){
if(cont>0){
pila->pop(); //respuesta 6
}else{
throw ; //respuesta 7
}
}
int size() const{
return pila->size();
}
};
class Figura{
public:
virtual void print(){
cout<< "FIGURA" <<endl;
}
};
class Circulo : public Figura{
public:
void print(){
cout<<"CIRCULO"<<endl;
}
};
class Triangulo : public Figura{
public:
void print(){
cout<<"TRIANGULO"<<endl;
}
};
int main(){
Pila<Figura*> *pfiguras= new Pila<Figura*>();
pfiguras->apilar(new Circulo());
pfiguras->apilar(new Triangulo());
Pila<Figura*> pfiguras2(*pfiguras);
pfiguras->tope()->print();
pfiguras->desapilar();
pfiguras->tope()->print();
pfiguras->desapilar();
pfiguras2.tope()->print();
system("Pause");
return 0;
}
Where to start? This has a lot of errors.
Don't have "using namespace std;", it clutters the global namespace. Rather, use std::list, std::cin, etc. using the namespace to identify the specific object or class.
In the exception class, don't write your own what() method. Just initialise the base class in the constructor.
class EPilaVacia : public std::exception
{
public:
EPilaVacia()
: std::exception("Error: Pila Vacía")
{
}
};
I assume that the class Pila is just a learning exercise. In real life you would use std::stack, not make your own.
If you are implementing the stack with a list, you don't need a "max" parameter.
Don't allocate the list dynamically, that is silly. Just use
std::list<T*> ila;
You don't need "cont". Use ila.size();
Don't make the functions like apilar() virtual. The list is private, so subclasses cannot access it, thus the methods cannot be overriden. Also, you don't have a virtual destructor, so inheritance is probably a bad idea.
void apilar(T t) is a disaster. You pass t by value, then store the address of the parameter, which then goes out of scope. The function is unnecessary, lose it.
Don't put "throw (EPilaVacia)" in method declarations. No compiler implements it and it is deprecated in the new C++11 standard.
In tope(), use ila.back(), not ila.pop_back().
T tope() const
{
if(ila.empty())
{
throw EPilaVacia();
}
else
{
return *ila.back();
}
}
In desapilar(), don't use clear as it will empty out the stack. Use something like this
T& desapilar()
{
if(ila.empty())
{
throw EPilaVacia();
}
else
{
T *pt = ila.back();
ila.pop_back();
return *pt;
}
}
NEVER use system("Pause"); Use std::cin.get();
The objects you allocate with new are never deleted. You have a memory leak.
There are probably more, but that should get you started.
Note: I've scrawled this down quickly. There are probably errors above, so check my code, don't just copy it.
Is this error happening on line "mystack=new stack<T>;" as that's the only line I see that might cause this. The reason for that is that mystack is defined as T*, not stack<T>. When the compiler tries to assign the new stack<T> to mystack, it sees that mystack is looking for T*, and says "I don't know how to make stack<T> into T*".
Now that you've fixed that error, you are getting a throw from nullptr exception. This would be best solved, normally, by running this under a debugger and seeing what line causes your program to behave poorly. However, by inspection, it appears that you're only pushing two things onto the stack, then try to use "top" to get a third: pfiguras2.tope()->print();.
You're also leaking memory, but Michael J's comment goes much better into the more nitpicky, less "make it not crash" area of this code.