-3

In my program, I get segmentation fault when calling

cout << ( ball(1,0,0) ).getName();

For testing purposes when i call
( ball(1,0,0) ).getName();

I get an exception as expected and program doesn't crash.

What might be wrong here? I tried overloading ostream but it didn't seem to work. The related parts of the program are:

Ball& Field::operator()(int x, int y, int z){

try{
    if (arr[x][y][z]==1){ // When it's 1, there is a ball in that coord 
        return search(root,x,y,z); // Return ball instance
    }else{

        throw ballException(); // 'Error: Ball not found'
    }
}catch(std::exception &e){
    std::cout << e.what() << std::endl;

}

}

const string& Ball::getName() const {

                try{
                    return this->name;

                }catch(std::exception & e){

                }


}

Ball::Ball(const string& name, const string& type, int size){
this->name =name;
this->type = type;
this->size= size;

}
Ball exception is:

 class ballException: public exception {
virtual const char* what() const throw() {
        return "Error: No Ball in the coordinates!";
}

};

shellnut
  • 25
  • 4

2 Answers2

1

You're not returning anything when you catch an exception:

Ball& Field::operator()(int x, int y, int z){
    try{
        if (arr[x][y][z]==1){ // When it's 1, there is a ball in that coord 
            return search(root,x,y,z); // Return ball instance
        }else{
            throw ballException(); // 'Error: Ball not found'
        }
    }catch(std::exception &e){
        std::cout << e.what() << std::endl;
    }
    // Nothing is returned.
}

Unless search also throws an exception, the exception handling is completely pointless, and the code is equivalent to

Ball& Field::operator()(int x, int y, int z){
    if (arr[x][y][z]==1){ // When it's 1, there is a ball in that coord 
        return search(root,x,y,z); // Return ball instance
    }
    // Returns nothing
}

Calling getName on that non-existing object may or may not appear to work – it's undefined.
(And it's more likely that you'll crash when trying to print the name that doesn't exist than if you just reference it.)

You probably want to handle the exception in the calling code rather than present that code with an object that doesn't exist:

Ball& Field::operator()(int x, int y, int z){
    if (arr[x][y][z]==1){
        return search(root,x,y,z);
    }else{
        throw ballException();
    }
}
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • I actually have the same exception handling inside the search() function but when i first wrote the function i got the same error so i switched back to if else one. What I'm wondering is, when i only call field(x,y,z).getName() i only get an exception. No crashes. If the problem is about not returning anything, why the program doesnt crash when i call field(x,y,z).getName() without cout < – shellnut May 06 '17 at 16:12
  • @shellnut It's undefined; anything can happen, including not crashing and carrying on as expected. (And if you're doing the same in `search`, it has the same problem. Don't over-use exceptions.) – molbdnilo May 06 '17 at 16:14
  • OK, while handling exception, I allocated a new Ball() object (pointer is bound to the class Field()),returned dereference of it from the catch block and it seems to work without a problem. But I feel like this is a really messy solution with all the allocation, deleting the extra Ball() object in destructor etc. and I can't edit the calling function with surrounding try{}catch block either.(because of homework) Is there a better solution than allocating a useless new Ball object? – shellnut May 06 '17 at 16:35
  • @shellnut Yes – let the exception continue out into the calling code and handle it there. Don't use exceptions for local error handling, that's not what they're for. – molbdnilo May 06 '17 at 16:39
0

When you do catch the exception, does foo( 0 ) still return an object upon which getName() can be called?

To use such syntax you usually have to return an empty (usually static) object upon which getName() is implemented, or to make sure of the state of the object before exiting the function. Below the general idea:

#include <exception>
#include <iostream>
#include <string>

class SomeObject
{
public:
    SomeObject(const std::string& name):_name(name)
    {
    }
    const std::string&  getName() const
    {
        return _name;
    };

    static const SomeObject& getEmpty()
    {
        static SomeObject _empty("");
        return _empty;
    };
private:

    std::string _name;

};


const SomeObject *function( bool throw_exception)
{
    SomeObject * NeverConstructed = 0;
    try {
        if ( throw_exception )
            throw std::runtime_error("oops");
    } catch ( const std::runtime_error& e) {
        std::cout << e.what() << std::endl;
        return &SomeObject::getEmpty();
    }

    return NeverConstructed; // will crash
}

int main(){

    std::cout << (function( true ))->getName() << std::endl;
    return 0;
}
didiz
  • 1,069
  • 13
  • 26
  • Thanks for the answer. I've edited the question to include full code of the related parts. According to your answer, should I return an empty Ball object while catching the exception? Since this is a homework I'm not supposed to implement a Ball() constructor without arguments. The only way to create a Ball object is to create it via Ball("name","type",size) and when I try to return a Ball object inside catch block I get errors. – shellnut May 06 '17 at 15:15
  • We need to see the whole code, specially the constructor. To return const std::string& you need to have a member called name and it must be initialized with new on the constructor. Otherwise that line will segfault for sure. – didiz May 06 '17 at 15:21