CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Nov 2002
    Posts
    5

    Question a basic c++ question

    class rational {
    public:
    rational(int numerator = 0, int denominator = 1);
    int numerator() const;
    int denominator() const;

    };

    who can tell me the meaning of this line?
    //rational(int numerator = 0, int denominator = 1);

    I know it's construct function. I want to know the meaning of " int numerator=0".

    Thanks

  2. #2
    Join Date
    Nov 2002
    Location
    India
    Posts
    8
    its a constructor with two arguments numerator and denomenator intialized with some values

  3. #3
    Join Date
    Nov 2002
    Posts
    5

    so, why ld encount error?

    Thank you for reply. But why link error?

    class rational {
    public:
    rational(int numerator = 0, int denominator = 1);
    int numerator() const;
    int denominator() const;

    };

    int rational::numerator() const {
    ........
    }


    int main()
    { rational r1;
    cout << r1.numerator() << endl;
    }

    The error is
    ld:
    Unresolved:
    rational::rational(int, int)
    *** Exit 1


    Thanks again.

  4. #4
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384
    Why ru not providing the definition for your contructor.
    When u have supplied default arguments then
    doing this
    Code:
    rational r1;
    or
    Code:
    rational r2(1,2);
    EDIT:
    OR
    Code:
    rational r3(1);
    Gets resolved to the Same constructor

    Code:
    rational(int a = 1, int b = 2);
    Hope this Helps,
    Regards,
    Usman.
    Last edited by usman999_1; November 7th, 2002 at 06:27 AM.

  5. #5
    Join Date
    Oct 2002
    Posts
    36
    Few ideas

    Code:
    #include <iostream>
    #include <exception>
    
    
    class rational {
    	int m_numerator;
    	int m_denominator;
    public:
    	rational(int _n = 0, int _d = 1) throw (std::exception)
    		:m_numerator(_n),m_denominator(_d){
     			//.....do whatever maybe;
     			if(m_denominator == 0)throw std::exception();
    	}
    	const int numerator(){return m_numerator;}
    	const int denominator(){return m_denominator;}
    };
    
    
    int main(){ 
    	try{
    		rational r1;
    		std::cout << r1.numerator()  << std::endl;
    		std::cout << r1.denominator() << std::endl;
    		
    		rational r2(10,50);
    		std::cout << r2.numerator()  << std::endl;
    		std::cout << r2.denominator() << std::endl;
    		
    		rational r3(50,0);//will throw!
    		std::cout << r3.numerator()  << std::endl;
    		std::cout << r3.denominator() << std::endl;		
    	}
    	catch(std::exception& e){
    		std::cout << "Exception caught!" << std::endl;
    	}
    }

  6. #6
    Join Date
    Nov 2002
    Posts
    5
    Thank you for dumah's professioal example. But I have one question for your sample code:

    What's the meaning of "throw " statement right after the constructor ?

    rational(int _n = 0, int _d = 1) throw (std::exception)
    :m_numerator(_n),m_denominator(_d){
    //.....do whatever maybe;
    if(m_denominator == 0)throw std::exception();
    }

  7. #7
    Join Date
    Oct 2002
    Posts
    36
    Sorry...yeah...its ans exception specifier - a kind of promise that the function wont throw any exceptions apart from those listed.

    throw() after a function means no exceptions will be thrown......not showing an exception specifier means the func can throw anything....

    I'm trying to get my exception handling better in my own code, so I'm trying to get in the habit...though I guess I was wrong to put it in a simple example as it would probably make it more confusing

  8. #8
    Join Date
    Nov 2002
    Posts
    5
    Thank you, dumah, I tried your sample and still a little confused about your word"throw() after a function means no exceptions will be thrown......not showing an exception specifier means the func can throw anything....". Thus, in previous code there are throw after the constructor, but there is exception.

    If I modified the constructor like this:

    rational(int _n = 0, int _d = 1) :m_numerator(_n),m_denominator(_d){
    if(m_denominator == 0)throw std::exception();
    }

    You can see this time no "throw()" func after the constructor. Will main() program catch some exception?

    I tried and it can also catch exception. So I want to know if throw() after the constructor or not can make difference.

    Thanks for your patience and time.

  9. #9
    Join Date
    Oct 2002
    Posts
    36
    Originally posted by younger2
    Thank you, dumah, I tried your sample and still a little confused about your word"throw() after a function means no exceptions will be thrown......not showing an exception specifier means the func can throw anything....". Thus, in previous code there are throw after the constructor, but there is exception.

    If I modified the constructor like this:

    rational(int _n = 0, int _d = 1) :m_numerator(_n),m_denominator(_d){
    if(m_denominator == 0)throw std::exception();
    }

    You can see this time no "throw()" func after the constructor. Will main() program catch some exception?

    I tried and it can also catch exception. So I want to know if throw() after the constructor or not can make difference.

    Thanks for your patience and time.
    You can certainly leave it out of the declaration...it just means that the constructor can throw any exception......in my code, the only thing that can be thrown is std::exception or anything derived from it.....In practice here, its not an issue, the exception will be caught....but if this code became a part of a big library, then its a nice guarantee for a user that the constructor can only throw 1 type of exception, so the user only provides for this 1 case.

    Interestingly, if you specify what exceptions are thrown and then break that promise, the exception is not thrown, but the app terminates. Look at the following, you would expect the exception to be caught, but it wont

    Code:
    #include <iostream>
    #include <exception>
    
    class foo{};//Some class
    
    void bar()throw(){//promise not to throw
    
    	throw foo();//break promise	
    }
    
    int main(){ 
    
    	try{	
    		bar();	
    	}
    	catch(...){//falsely expect all exceptions from bar to be caught
    	
    		std::cout << "Exception caught" << std::endl;
    		return 1;
    	}	
    	
    	std::cout << "No Exception caught" << std::endl;
    }
    What actually happens is a special handler is called, and that normally terminates.....you can specify a custom handler though like this

    Code:
    #include <iostream>
    #include <exception>
    #include <cstdlib>
    
    class foo{};//Some class
    
    void bar()throw(){//promise not to throw
    
    	throw foo();//break promise	
    }
    
    void My_Handler(){//handler to be called
    	
    	std::cout << "Handler invoked!!!" << std::endl;	
    	std::abort();
    }
    
    int main(){ 
    
    	std::set_unexpected(My_Handler);//set handler
    
    	try{	
    		bar();	
    	}
    	catch(...){//falsely expect all exceptions from bar to be caught
    	
    		std::cout << "Exception caught" << std::endl;
    		return 1;
    	}	
    	
    	std::cout << "No Exception caught" << std::endl;
    }
    Also interesting, you can rethrow in the handler and then the exception (which could theoretically be anything is changed into a std::bad_exception......so if you set the handler to rethrow, and then specify bad_exception, you will catch the exception no matter what was actually thrown.....this might be handy for misbehaving code that you have no access to...

    Code:
    #include <iostream>
    #include <exception>
    
    class foo{};//Some class
    
    void bar()throw(std::bad_exception){//throw bad_exception
    
    	throw foo();//break promise	
    }
    
    void My_Handler(){//handler to be called
    	
    	std::cout << "Handler invoked!!!" << std::endl;	
    	throw;
    }
    
    int main(){ 
    
    	std::set_unexpected(My_Handler);//set handler
    
    	try{	
    		bar();	
    	}
    	catch(std::exception){//note bad_exception is derived from exception
    	
    		std::cout << "Exception caught" << std::endl;
    		return 1;
    	}	
    	
    	std::cout << "No Exception caught" << std::endl;
    }
    Exceptions - tricky devils

  10. #10
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Originally posted by younger2
    Thank you, dumah, I tried your sample and still a little confused about your word"throw() after a function means no exceptions will be thrown......not showing an exception specifier means the func can throw anything....".
    The form of this function declaration is called exception specification. The essential benefit of an exception specification is that clients of a component know exactly what exceptions may be thrown from a function or a method. This can be great from the client perspective of handling exceptions, because the client knows exactly what exceptions, if any, may be thrown.

    Consider the following code:
    Code:
    class CFoo
    {
    public:
    void   FunctionWithOneExceptionSpecification() throw (ExceptionClass);
    void   FunctionThatThrowsNoExceptions() throw();
    };
    The first exception specification says that exceptions of type 'ExceptionClass' or derived from 'ExceptionClass' may be thrown from that method.

    However, to implement this specification you will most likely have to use a 'try'/'catch' block within the implementation of these methods to enforce the exception specification. Otherwise you run the risk of 'std::unexpected()' being called, the default behavior of which is to terminate the application. And since aborting the program execution is usually much more catastrophic than letting an exception propagate all the way up you have to fall back on using the 'try' block.

    The second function is declared as not throwing any kind of exception. However, if you did not write the function itself you will never know if this function still can throw an exception. Then you need to have a serious discussion with the developer of the function about exception handling...
    Last edited by Andreas Masur; November 7th, 2002 at 09:45 AM.

  11. #11
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    ... but the big problem with putting exception specifications in your code is that if you miss something then you run the risk of getting the dreaded "unexpected" exception. This will almost certainly result in an immediate crash. This is not a rare problem either: remember that your exception specification must include exceptions that can be thrown from anything that you call within the function. For example,
    Code:
    void f() throw(my_exception)
    {
        //......
        foo *f = new foo(); // new can throw std::bad_alloc
        //......
        if (something_bad_happens)
            throw my_exception;
    }
    This is a pretty trivial example, admittedly, and easily spotted, but it illustrates the point. If the new throws its exception, then f() is breaking its contract to only throw "my_exception", and the program will crash.

    About the only useful throw specification is "throw()" to explicitly state that this function will not throw under any circumstances. functions that swap two objects are often declared (and implemented!) as non-throwing functions, so that exception-safe copying can happen. For example:
    Code:
    class foo
    {
        int m1;
        int m2;
    
    public:
        //...
        foo(const foo&);
    
        foo& operator=(const foo& rhs)
        {
            foo temp(rhs);
            swap(temp);
            return *this;
        }
    
        void swap(foo& rhs) throw()
        {
            std::swap(m1, rhs.m1);
            std::swap(m2, rhs.m2);
        }
    };
    The function foo::swap is guaranteed not to throw an exception. foo::operator=() is exception safe since it makes a local copy of the rhs (which might throw) before committing that change. In other words, if the foo copy ctor throws, then the object being assigned to comes out of it unchanged (so you've got some hope of recovering). Only if the copy constructor succeeds does the object being assigned get modified, and that with a non-throwing swap.

    See Herb Sutter's Exceptional C++ for more detail.
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured