Question

I already saw this thread, however the situation is totally different and I can't apply that solution to my problem.

I have the following constructor:

Fan::Fan(Id id, std::string name, Age age);

Where Id and Age are typedef'ed unsigned int and unsigned short. This is given to me, so I know that I must use them, as most likely the tester of the assignment will try to use numbers bigger than int (in range of unsigned int / short).

Obviously, a Fan's id and age cannot be negative numbers. In the example code (to compile against), a fan is created with numbers for id and age. I cannot use string there and check for a minus sign.

I thought it wouldn't compile when I entered negative age / id in my unit testing. However, it turned out it did compile, and it gave random values (most likely due to overflow reasons).

So to conclude - it is possible to call the constructor with negative values for the age and id, but in the constructor their values get 'thrashed' and random numbers appear, and it causes unintended behavior.

For example, this:

Fan* fan = new Fan(-1, "Name", 9);

Compiles, and at run-time the id of the fan gets some unrelated value. So I must be able to detect the negative number in the constructor. How do I "block" the negative numbers in the constructor?

Thanks for your time! I hope my question is clear.

Was it helpful?

Solution

I created a small function template that checks whether the input lies within the range of the output data type, and throws an exception otherwise. It requires that the input and output data types are integral, and that the size of the input data type is larger than the output data type.

template<typename DestType, typename SrcType>
DestType range_check_and_convert(SrcType const& src)
{
    static_assert(sizeof(SrcType) > sizeof(DestType), 
        "SrcType must be larger than DestType");
    static_assert(std::is_integral<SrcType>::value &&
                  std::is_integral<DestType>::value, "integral types only");

    if(src > static_cast<SrcType>(std::numeric_limits<DestType>::max())) {
        throw std::out_of_range("input too big");
    } else if(src < static_cast<SrcType>(std::numeric_limits<DestType>::min())) {
        throw std::out_of_range("input too small");
    }

    return static_cast<DestType>(src);
}

Live demo

OTHER TIPS

By declaring the contructor to only take unsigned values you basically already "block" that negative numbers can be passed as parameters.

You can still write that you pass -1 to the function, but what the function then sees is the unsigned interpretation of that negative number, see this question.

For example in a 32-bit windows application passing -1 would result in an Id of 0xffffffff or 4294967295. Now you have to decide, whether this is a valid input for your application, but it probably is, because it's still a positive number. On the other hand an age of -1 is probably an invalid input, because it is unlikely to be 4294967295 years old. As you noticed, you can't check your unsigned value for -1. You have to check if age is bigger than for example 200, because -1 is effectively a large number when given as an unsigned parameter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top