简体   繁体   中英

How to validate input parameters in C++ constructor?

Following example shows the crux of the problem. I need to initialize const members of a class. This can only be done in the initializer-list and not in constructor body. I want to assert or throw an error if input to the constructor is invalid, that is, if the vector size is less than 3.

class A {
 // In following constructor, how do we make sure if params.size()
 // is at least 3.
 A(const std::vector<int>& params):
  x(params[0]), y(params[1]), z(params[2]) {}
private:
  const int x;
  const int y;
  const int z;
};

Please advise how to achieve this in Modern C++ (11 and later)

Just add a layer of abstraction. You can write a function that makes sure the vector is of the correct size and you can even make sure the values are in an expected range, if you have one. That would look like

class A {
 A(const std::vector<int>& params):
  x(verify(params, 0)), y(verify(params, 1)), z(verify(params, 3)) {}
private:
  static int verify(const std::vector<int>& params, int index) 
  { 
    if (params.size() < 4) // or use if (params.size() <= index) if you only care if the index will work
      throw something; 
    return params[index]; 
  }
  const int x;
  const int y;
  const int z;
};

const members can only be initialized in the constructors's member initialization list. To validate the caller's input, you would have to call a helper function to validate each input value before passing it to the corresponding member, eg:

int check(const std::vector<int> &params, int index) {
  if (params.size() <= index) throw std::length_error("");
  return params[index];
}

class A {
 A(const std::vector<int>& params):
  x(check(params, 0)), y(check(params, 1)), z(check(params, 3)) {}
private:
  const int x;
  const int y;
  const int z;
};

Or, simply utilize the vector 's own built-in bounds checking instead:

class A {
 A(const std::vector<int>& params):
  x(params.at(0)), y(params.at(1)), z(params.at(3)) {}
private:
  const int x;
  const int y;
  const int z;
};

Not as elegant as other solutions but... you can simply add a throw in a ternary operator inside the initialization of the first constant

class A
 {
   private:
      const int x;
      const int y;
      const int z;

   public:    
      A (const std::vector<int>& params)
         : x{ params.size() < 4u ? throw std::runtime_error{"!"}
                                 : params[0] },
           y{params[1]}, z{params[3]}
      { }
 };

Off Topic suggestion: if A is a class , maybe it's better that the constructor is public .

Other option extra layer through conversion:

class A_params{
   friend class A;
   int x;
   int y;
   int z;
   void validate();
   public:
   A_params(std::initializer_list<int>);
   A_params(const std::vector<int>&);
   A_params(int(&)[3]);
   //...
   };


class A {
 // In following constructor, how do we make sure if params.size()
 // is at least 3.
public:
 A(A_params params):
  x(params.x), y(params.y), z(params.z) {}
private:
  const int x;
  const int y;
  const int z;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM