Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting negative number

Tags:

c++

I have a code in which user has to pass > 0 number otherwise this code will throw. Using type of this arg as std::size_t doesn't work for the reason that negative numbers give large positive numbers. Is it good practice if I use signed type or are there other ways to enforce it?

void f(std::size_t number)
{
//if -1 is passed I'm (for obvious reason) get large positive number
}
like image 893
There is nothing we can do Avatar asked Dec 28 '22 05:12

There is nothing we can do


2 Answers

I don't think there's a definitive correct answer to this question. You can take an look to Scott Meyers's opinion on the subject :

One problem is that unsigned types tend to decrease your ability to detect common programming errors. Another is that they often increase the likelihood that clients of your classes will use the classes incorrectly.

In the end, the question to ask is really : do you need the extra possible values provided by the unsigned type ?

like image 200
icecrime Avatar answered Jan 13 '23 20:01

icecrime


A lot depends on what type of argument you imagine your clients trying to pass. If they're passing int, and that's clearly big enough to hold the range of values you're going to use, then there's no practical advantage to using std::size_t - it won't enforce anything, and the way the issue manifests as an apparently huge number is simply more confusing.

BUT - it is good to use size_t anyway as it helps document the expectations of the API.

You clearly can't do a compile-time check for "> 0" against a run-time generated value, but can at least disambiguate negative inputs from intentional huge numbers ala

template <typename T>
void f(T t)
{
    if (!(t > 0))
        throw std::runtime_error("be positive!");

    // do stuff with t, knowing it's not -1 shoehorned into size_t...
    ...
}

But, if you are really concerned about this, you could provide overloads:

// call me please e.g. f(size_t(10));
void f(size_t);

// unimplemented (and private if possible)... 
// "want to make sure you realise this is unsigned: call f(size_t) explicitly
void f(int32_t);
void f(int64_t);

...then there's a compile-time error leading to the comments re caller explicitly providing a size_t argument (casting if necessary). Forcing the client to provide an arg of size_t type is a pretty good way to make sure they're conscious of the issue.

Rin's got a good idea too - would work really well where it works at all (depends on there being an signed int type larger than size_t). Go check it out....

EDIT - demonstration of template idea above...

#include <iostream>                                                             

template <typename T>                                                           
void f(T t)                                                                     
{                                                                               
    if (!(t > 0))                                                               
        std::cout << "bad call f(" << (int)t << ")\n";                               
    else                                                                        
        std::cout << "good f(" << (int)t << ")\n";                                   
}                                                                               

int main()                                                                      
{                                                                               
    f((char)-1);
    f((unsigned char)255);                                                     
}
like image 39
Tony Delroy Avatar answered Jan 13 '23 20:01

Tony Delroy