-3

So, I want to restrict making objects without parameters given in constructor using try-throw-catch. Here's what I've written so far. But it's not working properly, what should I do? No errors, just returns 0.

#include <iostream>

using namespace std;

class Person
{
    public:
        Person(int _age)
        {
            age = _age;

            try
            {
                if (age == -1)
                {
                    throw 1;
                }
            }

            catch (int x)
            {
                cout << "You have to specify person's age" << endl;
            }
        }

    private:
        int age = -1;
};

int main(void)
{
    Person a();
    return 0;
}
PoorProgrammer
  • 111
  • 1
  • 2
  • 9
  • 4
    `Person a();` is a declaration of a function taking no parameters and returning a `Person`. It's not a definition of a variable of type `Person`. You could write `Person a;` or `Person a{};` - those won't compile since `Person` doesn't have a default constructor. – Igor Tandetnik Nov 07 '17 at 23:03
  • The proper of doing this is having the try-catch in the ``main`` function where you're creating a ``Person`` instance. With this, the ``Person`` instance is created even if the age is invalid and the question is, should a ``Person`` object be allowed to have an invalid age? – SameOldNick Nov 07 '17 at 23:05
  • Also, even if you say `Person a;`, that won't compile because the default constructor will not have been synthesised, as you have provided a non-default constructor. –  Nov 07 '17 at 23:06
  • So, the way to solve this problem is to create a default constructor and write the same try-catch-throw construction there, then delete the object and close the program? – PoorProgrammer Nov 07 '17 at 23:10
  • 4
    If you don't want the function to be called without parameters do not make a default constructor. – user4581301 Nov 07 '17 at 23:16
  • 1
    Your code allows a Person to be created with age -5. You may want to consider `age` as an *unsigned* integer, since negative ages don't make sense. – Thomas Matthews Nov 08 '17 at 00:46

1 Answers1

2

Problem 1:

Person a();

A vexing parse. This does not declare a variable and invoke the constructor, it declares function a that returns a Person.

Solution:

Person a;

but this sets up problem 2:

There is no default constructor. Specifying Person(int _age) defines a non-default constructor and this blocks the compiler from generating a default (parameter-less) constructor. This is actually a win for you because your stated goal is to not be able to construct a Person without parameters.

You cannot

Person a;

You must

Person a(<an int>);

This does not prevent a user from

Person a(-1);

Which makes little sense for anyone not from Ork. This sets up a great example for use of an exception in a constructor and exposes problem 3:

There are two ways out of a constructor that don't end the program: With a constructed object and by a thrown exception. Both throwing and catching an exception that signals construction has failed in a constructor is unusual because it allows an improperly constructed object to be returned.

So

Person(int _age)
{
    age = _age;

    try
    {
        if (age == -1) // probably should reject age < 0
        {
            throw 1;
        }
    }

    catch (int x)
    {
        cout << "You have to specify person's age" << endl;
    }
}

Actually causes the problem you are trying to avoid.

Solution:

Person(int _age)
{
    age = _age;
    if (age == -1)
    {
        throw 1;
    }
}

and in main

int main(void)
{
    try
    { 
        Person a();
        // use a
        return 0;
    }
    catch (int x)
    {
        cout << "You have to specify person's age" << endl;
        return -1;
    }
}

There is one big improvement that can be made: Make exceptions meaningful

Throwing 1 contains too little context to be meaningful. You can throw and catch a custom exception, but for something simple like this std::runtime_error from `

Person(int _age)
{
    if (_age == -1)
    {
        throw std::runtime_error("You have to specify person's age");
        // do not new an exception. It's hard to clean up and free the memory
    }
    age = _age; // why assign then test? Save a clock cycle.
}

and in main

int main(void)
{
    try
    { 
        Person a();
        // use a
        return 0;
    }
    catch (const std::exception & e) // where possible catch by constant reference
    {
        cout << e.what() << endl;
        return -1;
    }
}
user4581301
  • 33,082
  • 7
  • 33
  • 54