-1

I am using gcc10.2, c++20.

I am studying c++ after 2 years of python.

In python we always did run-time check for input validity

def createRectangle(x, y, width, height): # just for example
    for v in [x, y, width, height]:
        if v < 0:
            raise ValueError("Cant be negative")
    # blahblahblah

How would I do such process in c++?

Inyoung Kim 김인영
  • 1,434
  • 1
  • 17
  • 38

2 Answers2

4
for (int v : {x, y, width, height})
    if (v < 0)
        throw std::runtime_error("Can't be negative");

Note that such loop copies each variable twice. If your variables are heavy to copy (e.g. containers), use pointers instead:

for (const int *v : {&x, &y, &width, &height})
    if (*v < 0)
        ...

Comments also suggest using a reference, e.g. for (const int &v : {x, y, width, height}), but that will still give you one copy per variable. So if a type is that heavy, I'd prefer pointers.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
1

In C++:

  1. Use an appropriate type so validation (at the point you use the variables as opposed to setting them up from some input) is unnecessary, e.g. unsigned for a length. C++ is more strongly typed than Python, so you don't need large validation checks to make sure the correct type is passed to a function.

  2. A throw is broadly equivalent to a raise in Python. In C++, we tend to derive an exception from std::exception, and throw that.

Boost (www.boost.org) has a nice validation library which is well-worth looking at.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    C++ doesn't have `unsigned double` though ;-) (Yes, I saw before the edit :-) ) – Jarod42 Mar 08 '21 at 13:46
  • 1
    I disagree with point 1. Using `unsigned` *hides* errors. If a user calls the function with a negative number, there's no good way of checking if they made a mistake. – cigien Mar 08 '21 at 13:46
  • @Jarod42: There's no hiding here, even with the 5 minute grace period. – Bathsheba Mar 08 '21 at 13:46
  • @cigien: It only hides errors if you're having a senior moment when dealing with IO. – Bathsheba Mar 08 '21 at 13:47
  • 1
    Taking an unsigned for size is a bad idea: https://wandbox.org/permlink/BkoEtG7Jy6qCmwqs. You really shouldn't use it for must be positive values. – NathanOliver Mar 08 '21 at 13:47
  • Some compiler might provide warning for implicit signed->unsigned conversion (Lot of noise most of the time :-/) – Jarod42 Mar 08 '21 at 13:48
  • @NathanOliver: For me that's dogmatic. The arguments around `unsigned` types will rumble on until a language that replaces C++ emerges. – Bathsheba Mar 08 '21 at 13:48
  • 1
    I saw the `operator >>` as "broken" in that regard... – Jarod42 Mar 08 '21 at 13:50
  • So to clarify: your latest edit is suggesting that *every* caller of this function should now switch over to using `unsigned` so that they don't make a mistake while calling it? What about values that the calling code receives from other sources? It sounds like you're suggesting the entire program should switch over to `unsigned`. What about existing `signed` values that need to be signed, and interactions with them? I have to say this sounds like poor advice. – cigien Mar 08 '21 at 13:53
  • I agree that taking an `unsigned` is the most explicit way. If someone tries to pass an `int`, they *should* get a warning about the implicit conversion, which is better than a runtime exception. – Aykhan Hagverdili Mar 08 '21 at 13:54
  • @cigien callers should check for negative before calling, then add an explicit cast. It's like taking by reference instead of pointer so callers must check for null before calling. – Aykhan Hagverdili Mar 08 '21 at 13:55
  • @cigien [`gsl::narrow_cast`](https://github.com/microsoft/GSL/blob/main/include/gsl/util) ? – Caleth Mar 08 '21 at 13:55
  • 1
    @AyxanHaqverdili I'm fine with changing a function in a way that *forces* the caller to do something, but taking an `unsigned` parameter doesn't do that. At best, it gives a warning, and that can be ignored. Caleth's suggestion to use `gsl::narrow_cast` has the similar problem, in that the caller is not required to use it. My issue with this `unsigned` argument is that the function gets an illusion of safety that simply is not guaranteed. – cigien Mar 08 '21 at 13:58
  • @cigien: you might still have a `safe_unsigned_int` class with `delete` constructor from signed, and (explicit) constructor from unsigned :-) – Jarod42 Mar 08 '21 at 14:11